@@ -101,17 +101,19 @@ class _NoUpdate(object):
101
101
ns["{function_name}"] = {clientside_function};
102
102
"""
103
103
104
-
105
- def _handle_callback_args (args , kwargs ):
104
+ def extract_callback_args (args , kwargs , name , type_ ):
105
+ """Extract arguments for callback from a name and type"""
106
+ print (args , kwargs )
107
+ parameters = kwargs .get (name , [])
108
+ if not parameters :
109
+ while args and isinstance (args [0 ], type_ ):
110
+ parameters .append (args .pop (0 ))
111
+ return parameters
112
+
113
+ def _handle_callback_args (* args , ** kwargs ):
106
114
"""Split args into outputs, inputs and states"""
107
- prevent_initial_call = None
108
- for k , v in kwargs .items ():
109
- if k == "prevent_initial_call" :
110
- prevent_initial_call = v
111
- else :
112
- raise TypeError (
113
- "callback got an unexpected keyword argument '{}'" .format (k )
114
- )
115
+ prevent_initial_call = kwargs .get ('prevent_initial_call' , None )
116
+ # flatten args
115
117
args = [
116
118
arg
117
119
# for backward compatibility, one arg can be a list
@@ -121,14 +123,17 @@ def _handle_callback_args(args, kwargs):
121
123
arg_or_list if isinstance (arg_or_list , (list , tuple )) else [arg_or_list ]
122
124
)
123
125
]
126
+ outputs = extract_callback_args (args , kwargs , 'output' , Output )
127
+ inputs = extract_callback_args (args , kwargs , 'inputs' , Input )
128
+ states = extract_callback_args (args , kwargs , 'state' , State )
129
+
130
+ if args :
131
+ raise TypeError (
132
+ "callback must received first all Outputs, then all Inputs, then all States" )
124
133
return [
125
- # split according to type Output, Input, State
126
- [arg for arg in args if isinstance (arg , class_ )]
127
- for class_ in [Output , Input , State ]
128
- ] + [
129
- # keep list of args in order, for matching order
130
- # in the callback's parameters
131
- [arg for arg in args if not isinstance (arg , Output )],
134
+ outputs ,
135
+ inputs ,
136
+ states ,
132
137
prevent_initial_call ,
133
138
]
134
139
@@ -857,7 +862,7 @@ def dependencies(self):
857
862
return flask .jsonify (self ._callback_list )
858
863
859
864
def _insert_callback (
860
- self , output , inputs , state , callback_args , prevent_initial_call
865
+ self , output , inputs , state , prevent_initial_call
861
866
):
862
867
if prevent_initial_call is None :
863
868
prevent_initial_call = self .config .prevent_initial_callbacks
@@ -868,14 +873,12 @@ def _insert_callback(
868
873
"output" : callback_id ,
869
874
"inputs" : [c .to_dict () for c in inputs ],
870
875
"state" : [c .to_dict () for c in state ],
871
- "args" : [c .to_dict () for c in callback_args ],
872
876
"clientside_function" : None ,
873
877
"prevent_initial_call" : prevent_initial_call ,
874
878
}
875
879
self .callback_map [callback_id ] = {
876
880
"inputs" : callback_spec ["inputs" ],
877
881
"state" : callback_spec ["state" ],
878
- "args" : callback_spec ["args" ],
879
882
}
880
883
self ._callback_list .append (callback_spec )
881
884
@@ -996,18 +999,21 @@ def callback(self, *args, **kwargs):
996
999
not to fire when its outputs are first added to the page. Defaults to
997
1000
`False` unless `prevent_initial_callbacks=True` at the app level.
998
1001
"""
1002
+ kwargs ['prevent_initial_call' ] = kwargs .get (
1003
+ 'prevent_initial_call' , None )
1004
+ output = kwargs .get ('output' , args [0 ])
999
1005
# for backward compatibility, store whether first argument is a
1000
1006
# list of only 1 Output
1001
- specified_output_list = isinstance (args [0 ], (list , tuple )) and len (args [0 ]) == 1
1007
+ specified_output_list = (
1008
+ isinstance (output , (list , tuple )) and len (output ) == 1 )
1002
1009
(
1003
1010
output ,
1004
1011
inputs ,
1005
1012
state ,
1006
- callback_args ,
1007
1013
prevent_initial_call ,
1008
- ) = _handle_callback_args (args , kwargs )
1014
+ ) = _handle_callback_args (* args , ** kwargs )
1009
1015
callback_id = self ._insert_callback (
1010
- output , inputs , state , callback_args , prevent_initial_call
1016
+ output , inputs , state , prevent_initial_call
1011
1017
)
1012
1018
1013
1019
def wrap_func (func ):
@@ -1078,15 +1084,7 @@ def dispatch(self):
1078
1084
1079
1085
response = flask .g .dash_response = flask .Response (mimetype = "application/json" )
1080
1086
1081
- # frontend sends inputs and state in separate variables
1082
- # we need to reorder them for the callback
1083
- args_inputs = [
1084
- value
1085
- for arg in self .callback_map [output ]["args" ]
1086
- for value in (inputs + state )
1087
- if arg ["id" ] == value ["id" ] and arg ["property" ] == value ["property" ]
1088
- ]
1089
- args = inputs_to_vals (args_inputs )
1087
+ args = inputs_to_vals (inputs + state )
1090
1088
1091
1089
func = self .callback_map [output ]["callback" ]
1092
1090
response .set_data (func (* args , outputs_list = outputs_list ))
0 commit comments