@@ -383,6 +383,15 @@ def run(self, *args, **kwargs):
383383 def register_blueprint (self , * args , ** kwargs ):
384384 pass
385385
386+
387+ def compare (id_python , id_dash ):
388+ """Compare an id of a dash component as a python object with an id of a component
389+ in dash syntax. It handles both id as str or as dict (pattern-matching)"""
390+ if isinstance (id_python , dict ):
391+ return "{" in id_dash and id_python == json .loads (id_dash )
392+ return id_python == id_dash
393+
394+
386395class WrappedDash (Dash ):
387396 'Wrapper around the Plotly Dash application instance'
388397 # pylint: disable=too-many-arguments, too-many-instance-attributes
@@ -436,10 +445,16 @@ def augment_initial_layout(self, base_response, initial_arguments=None):
436445 if initial_arguments :
437446 if isinstance (initial_arguments , str ):
438447 initial_arguments = json .loads (initial_arguments )
448+ else :
449+ initial_arguments = {}
450+
451+ # Define overrides as self._replacements updated with initial_arguments
452+ overrides = dict (self ._replacements )
453+ overrides .update (initial_arguments )
439454
440455 # Walk tree. If at any point we have an element whose id
441456 # matches, then replace any named values at this level
442- reworked_data = self .walk_tree_and_replace (baseData , initial_arguments )
457+ reworked_data = self .walk_tree_and_replace (baseData , overrides )
443458
444459 response_data = json .dumps (reworked_data ,
445460 cls = PlotlyJSONEncoder )
@@ -473,10 +488,15 @@ def walk_tree_and_replace(self, data, overrides):
473488 replacements = {}
474489 # look for id entry
475490 thisID = data .get ('id' , None )
476- if thisID is not None :
477- replacements = overrides .get (thisID , None ) if overrides else None
478- if not replacements :
479- replacements = self ._replacements .get (thisID , {})
491+ if isinstance (thisID , dict ):
492+ # handle case of thisID being a dict (pattern) => linear search in overrides dict
493+ for k , v in overrides .items ():
494+ if compare (id_python = thisID , id_dash = k ):
495+ replacements = v
496+ break
497+ elif thisID is not None :
498+ # handle standard case of string thisID => key lookup
499+ replacements = overrides .get (thisID , {})
480500 # walk all keys and replace if needed
481501 for k , v in data .items ():
482502 r = replacements .get (k , None )
@@ -628,15 +648,15 @@ def dispatch_with_args(self, body, argMap):
628648
629649 for component_registration in callback_info ['inputs' ]:
630650 for c in inputs :
631- if c ['property' ] == component_registration ['property' ] and c ['id' ] == component_registration ['id' ]:
651+ if c ['property' ] == component_registration ['property' ] and compare ( id_python = c ['id' ], id_dash = component_registration ['id' ]) :
632652 v = c .get ('value' , None )
633653 args .append (v )
634654 if da :
635655 da .update_current_state (c ['id' ], c ['property' ], v )
636656
637657 for component_registration in callback_info ['state' ]:
638658 for c in states :
639- if c ['property' ] == component_registration ['property' ] and c ['id' ] == component_registration ['id' ]:
659+ if c ['property' ] == component_registration ['property' ] and compare ( id_python = c ['id' ], id_dash = component_registration ['id' ]) :
640660 v = c .get ('value' , None )
641661 args .append (v )
642662 if da :
@@ -670,6 +690,9 @@ def dispatch_with_args(self, body, argMap):
670690 if da .have_current_state_entry (output_id , output_property ):
671691 value = root_value .get (output_id ,{}).get (output_property , None )
672692 da .update_current_state (output_id , output_property , value )
693+ else :
694+ # todo: implement saving of state for pattern matching ouputs
695+ raise NotImplementedError ("Updating state for dict keys (pattern matching) is not yet implemented" )
673696
674697 return res
675698
0 commit comments