@@ -475,6 +475,62 @@ def _validate_callback(self, output, inputs, state, events):
475
475
output .component_id ,
476
476
output .component_property ).replace (' ' , '' ))
477
477
478
+ def _validate_callback_output (self , output_value , output ):
479
+ valid = [str , dict , int , float , type (None ), Component , dict ]
480
+
481
+ def _raise_invalid (bad_val , outer_type , bad_type , path , index = None ):
482
+ raise exceptions .ReturnValueNotJSONSerializable ('''
483
+ The callback for property `{:s}` of component `{:s}`
484
+ returned a tree with one value having type `{:s}`
485
+ which is not JSON serializable.
486
+
487
+ The value in question is located at
488
+
489
+ `{:s}`
490
+
491
+ and has string representation
492
+
493
+ `{}`.
494
+
495
+ In general, Dash properties can only be
496
+ dash components, strings, dictionaries, numbers, None,
497
+ or lists of those.
498
+ ''' .format (
499
+ output .component_property ,
500
+ output .component_id ,
501
+ bad_type ,
502
+ (
503
+ "outer list index {:d} ({:s}) -> "
504
+ .format (index , outer_type )
505
+ if index is not None
506
+ else (outer_type + " -> " )
507
+ ) + path ,
508
+ bad_val ).replace (' ' , '' ))
509
+
510
+ def _value_is_valid (val ):
511
+ return (
512
+ # pylint: disable=unused-variable
513
+ any ([isinstance (val , x ) for x in valid ]) or
514
+ type (val ).__name__ == 'unicode'
515
+ )
516
+
517
+ def _validate_value (val , index = None ):
518
+ if isinstance (val , Component ):
519
+ for p , j in val .traverse_with_paths ():
520
+ if not _value_is_valid (j ):
521
+ _raise_invalid (j , type (val ).__name__ , type (j ).__name__ ,
522
+ p , index )
523
+ else :
524
+ if not _value_is_valid (val ):
525
+ _raise_invalid (val , type (val ).__name__ , type (val ).__name__ ,
526
+ '' , index )
527
+
528
+ if isinstance (output_value , list ):
529
+ for i , val in enumerate (output_value ):
530
+ _validate_value (val , index = i )
531
+ elif isinstance (output_value , Component ):
532
+ _validate_value (output_value )
533
+
478
534
# TODO - Update nomenclature.
479
535
# "Parents" and "Children" should refer to the DOM tree
480
536
# and not the dependency tree.
@@ -513,6 +569,7 @@ def wrap_func(func):
513
569
def add_context (* args , ** kwargs ):
514
570
515
571
output_value = func (* args , ** kwargs )
572
+ self ._validate_callback_output (output_value , output )
516
573
response = {
517
574
'response' : {
518
575
'props' : {
0 commit comments