@@ -229,7 +229,8 @@ def get_attributes_dicts(object_name, parent_object_names=()):
229
229
return attributes_dicts
230
230
231
231
232
- def get_valid_attributes (object_name , parent_object_names = ()):
232
+ @utils .memoize ()
233
+ def _get_valid_attributes (object_name , parent_object_names ):
233
234
attributes = get_attributes_dicts (object_name , parent_object_names )
234
235
# These are for documentation and quick lookups. They're just strings.
235
236
valid_attributes = set ()
@@ -245,6 +246,11 @@ def get_valid_attributes(object_name, parent_object_names=()):
245
246
return valid_attributes
246
247
247
248
249
+ def get_valid_attributes (object_name , parent_object_names = ()):
250
+ # Enforce that parent_object_names is hashable (a tuple).
251
+ return _get_valid_attributes (object_name , tuple (parent_object_names ))
252
+
253
+
248
254
def get_deprecated_attributes (object_name , parent_object_names = ()):
249
255
attributes = get_attributes_dicts (object_name , parent_object_names )
250
256
# These are for documentation and quick lookups. They're just strings.
@@ -340,21 +346,10 @@ def attribute_path_to_object_names(attribute_container_path):
340
346
return tuple (object_names )
341
347
342
348
343
- def get_role (object_name , attribute , value = None , parent_object_names = ()):
344
- """
345
- Values have types associated with them based on graph_reference.
346
-
347
- 'data' type values are always kept
348
- 'style' values are kept if they're sequences (but not strings)
349
-
350
- :param (str) object_name: The name of the object containing 'attribute'.
351
- :param (str) attribute: The attribute we want the `role` of.
352
- :param (*) value: If the value is an array, the return can be different.
353
- :param parent_object_names: An iterable of obj names from graph reference.
354
- :returns: (str) This will be 'data', 'style', or 'info'.
355
-
356
- """
357
- if object_name in TRACE_NAMES and attribute == 'type' :
349
+ @utils .memoize ()
350
+ def _get_role (object_name , attribute , value_type , parent_object_names = ()):
351
+ """Private, more easily memoized version of get_role."""
352
+ if attribute == 'type' and object_name in TRACE_NAMES :
358
353
return 'info'
359
354
attributes_dicts = get_attributes_dicts (object_name , parent_object_names )
360
355
matches = []
@@ -372,12 +367,8 @@ def get_role(object_name, attribute, value=None, parent_object_names=()):
372
367
for match in matches :
373
368
role = match ['role' ]
374
369
array_ok = match .get ('arrayOk' )
375
- if value is not None and array_ok :
376
- iterable = hasattr (value , '__iter__' )
377
- stringy = isinstance (value , six .string_types )
378
- dicty = isinstance (value , dict )
379
- if iterable and not stringy and not dicty :
380
- role = 'data'
370
+ if array_ok and value_type == 'array' :
371
+ role = 'data'
381
372
roles .append (role )
382
373
383
374
# TODO: this is ambiguous until the figure is in place...
@@ -388,6 +379,36 @@ def get_role(object_name, attribute, value=None, parent_object_names=()):
388
379
return role
389
380
390
381
382
+ def get_role (object_name , attribute , value = None , parent_object_names = ()):
383
+ """
384
+ Values have types associated with them based on graph_reference.
385
+
386
+ 'data' type values are always kept
387
+ 'style' values are kept if they're sequences (but not strings)
388
+
389
+ :param (str) object_name: The name of the object containing 'attribute'.
390
+ :param (str) attribute: The attribute we want the `role` of.
391
+ :param (*) value: If the value is an array, the return can be different.
392
+ :param parent_object_names: An iterable of obj names from graph reference.
393
+ :returns: (str) This will be 'data', 'style', or 'info'.
394
+
395
+ """
396
+ if value is None :
397
+ value_type = 'none'
398
+ elif isinstance (value , dict ):
399
+ value_type = 'dict'
400
+ elif isinstance (value , six .string_types ):
401
+ value_type = 'string'
402
+ elif hasattr (value , '__iter__' ):
403
+ value_type = 'array'
404
+ else :
405
+ value_type = 'unknown'
406
+
407
+ # Enforce that parent_object_names is hashable (a tuple).
408
+ return _get_role (object_name , attribute , value_type ,
409
+ tuple (parent_object_names ))
410
+
411
+
391
412
def _is_valid_sub_path (path , parent_paths ):
392
413
"""
393
414
Check if a sub path is valid given an iterable of parent paths.
0 commit comments