@@ -369,32 +369,50 @@ def _sym_missing(self) -> typing.Dict[str, Any]:
369
369
def _sym_nondefault (self ) -> typing .Dict [str , Any ]:
370
370
"""Returns non-default values as key/value pairs in a dict."""
371
371
non_defaults = dict ()
372
- if self ._value_spec and self ._value_spec .schema :
372
+ if self ._value_spec is not None and self ._value_spec .schema :
373
373
dict_schema = self ._value_spec .schema
374
- matched_keys , unmatched_keys = dict_schema .resolve (self .keys ())
375
- assert not unmatched_keys
374
+ matched_keys , _ = dict_schema .resolve (self .keys ())
376
375
for key_spec , keys in matched_keys .items ():
377
376
value_spec = dict_schema [key_spec ].value
378
377
for key in keys :
379
- v = self .sym_getattr (key )
380
- child_has_non_defaults = False
381
- if isinstance (v , base .Symbolic ):
382
- non_defaults_child = v .non_default_values (flatten = False )
383
- if non_defaults_child :
384
- non_defaults [key ] = non_defaults_child
385
- child_has_non_defaults = True
386
- if not child_has_non_defaults and value_spec .default != v :
387
- non_defaults [key ] = v
378
+ diff = self ._diff_base (self .sym_getattr (key ), value_spec .default )
379
+ if pg_typing .MISSING_VALUE != diff :
380
+ non_defaults [key ] = diff
388
381
else :
389
382
for k , v in self .sym_items ():
390
383
if isinstance (v , base .Symbolic ):
391
- non_defaults_child = v .non_default_values (flatten = False )
384
+ non_defaults_child = v .sym_nondefault (flatten = False )
392
385
if non_defaults_child :
393
386
non_defaults [k ] = non_defaults_child
394
387
else :
395
388
non_defaults [k ] = v
396
389
return non_defaults
397
390
391
+ def _diff_base (self , value : Any , base_value : Any ) -> Any :
392
+ """Computes the diff between a value and a base value."""
393
+ if base .eq (value , base_value ):
394
+ return pg_typing .MISSING_VALUE
395
+
396
+ if (isinstance (value , list )
397
+ or not isinstance (value , base .Symbolic )
398
+ or pg_typing .MISSING_VALUE == base_value ):
399
+ return value
400
+
401
+ if value .__class__ is base_value .__class__ :
402
+ getter = lambda x , k : x .sym_getattr (k )
403
+ elif isinstance (value , dict ) and isinstance (base_value , dict ):
404
+ getter = lambda x , k : x [k ]
405
+ else :
406
+ return value
407
+
408
+ diff = {}
409
+ for k , v in value .sym_items ():
410
+ base_v = getter (base_value , k )
411
+ child_diff = self ._diff_base (v , base_v )
412
+ if pg_typing .MISSING_VALUE != child_diff :
413
+ diff [k ] = child_diff
414
+ return diff
415
+
398
416
def seal (self , sealed : bool = True ) -> 'Dict' :
399
417
"""Seals or unseals current object from further modification."""
400
418
if self .is_sealed == sealed :
@@ -796,7 +814,7 @@ def sym_jsonify(
796
814
value = self .sym_getattr (key )
797
815
if pg_typing .MISSING_VALUE == value :
798
816
continue
799
- if hide_default_values and value == field .default_value :
817
+ if hide_default_values and base . eq ( value , field .default_value ) :
800
818
continue
801
819
json_repr [key ] = base .to_json (
802
820
value , hide_default_values = hide_default_values , ** kwargs )
@@ -886,7 +904,7 @@ def _should_include_key(key):
886
904
if pg_typing .MISSING_VALUE == v :
887
905
if hide_missing_values :
888
906
continue
889
- elif hide_default_values and v == field .default_value :
907
+ elif hide_default_values and base . eq ( v , field .default_value ) :
890
908
continue
891
909
field_list .append ((field , key , v ))
892
910
else :
0 commit comments