[python] fix null handling in generated models

Merged
FA
3mo ago
+217-316

Fixes a few ways the python generator mishandles null when (de)serializing models.

to_dict() drops null entries from containers

to_dict() rebuilds containers of models by hand and skipped falsy entries, so None items disappeared:

Container(items=[item, None]).to_dict()          # -> {'items': [{...}]}          length changed!
Container(mapping={'a': None, 'b': item}).to_dict()  # -> {'mapping': {'b': {...}}}   key 'a' gone

A dropped element shifts every following index for the consumer, and a dropped map key is just lost. Now the None is kept as an explicit null. The list-of-list / list-of-dict from_dict comprehensions also crashed on a null inner container ('NoneType' object has no attribute ...); those are guarded too.

from_dict() resurrects the default over an explicit null

For a nullable property with a default, from_dict used obj.get(k) if obj.get(k) is not None else <default>, so an explicit JSON null was indistinguishable from an absent key and got replaced by the default:

# property: {type: string, nullable: true, default: "hello"}
Container.from_dict({"note": None}).note   # -> "hello"   (should be None)

This round-trips as silent data corruption (from_json(x.to_json()) turns an intentional None back into the default). Changed to check key presence for nullable properties; non-nullable properties keep the old behavior.

get_discriminator_value() raises KeyError instead of ValueError

When the discriminator property is missing from the payload, obj[cls.__discriminator_property_name] raised a bare KeyError, while the code a few lines below builds a descriptive ValueError for unmapped values. The rest of the deserialization stack catches ValueError, so the KeyError leaked out. Switched to obj.get().

Verified list/map null preservation, nullable-default round-trips, and the discriminator path against generated clients; petstore sample tests still pass.

PR checklist

  • Read the contribution guidelines.
  • Ran ./mvnw clean package and regenerated the python samples.
  • Filed the PR against master.

/cc @cbornet @tomplus @krjakbrjak


Summary by cubic

Fix incorrect null handling in generated python models to preserve data shape during (de)serialization and align error behavior with the rest of the stack. Keeps explicit None values and avoids crashes with null inner containers.

  • Bug Fixes
    • Preserve None entries in lists and dict values in to_dict(); use single conditional expressions for container items to keep mypy happy.
    • For nullable properties with defaults, from_dict() checks key presence so an explicit null isn’t replaced by the default; non-nullable behavior unchanged.
    • Guard from_dict() list-of-list and list-of-dict comprehensions so null inner containers don’t crash.
    • Use obj.get() in discriminator lookup so a missing discriminator raises a descriptive ValueError instead of a KeyError.