Skip to content

Commit

Permalink
Merge pull request #263 from cwacek/fix/218
Browse files Browse the repository at this point in the history
bugfix: Fix #218 by serializing "null" for "null" types
  • Loading branch information
cwacek authored Sep 14, 2023
2 parents d122ce8 + 3d78861 commit 82b1fb4
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 18 deletions.
17 changes: 13 additions & 4 deletions python_jsonschema_objects/classbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ def as_dict(self):
out[prop] = [getattr(x, "for_json", lambda: x)() for x in propval]
elif isinstance(propval, (ProtocolBase, LiteralValue)):
out[prop] = propval.as_dict()
elif propval is not None:
elif (
propval is not None
or self.__propinfo__[prop].get("type", None) == "null"
):
out[prop] = propval

return out
Expand Down Expand Up @@ -150,9 +153,6 @@ def __new__(cls, **props):
obj = None
validation_errors = []
for klass in valid_types:
logger.debug(
util.lazy_format("Attempting to instantiate {0} as {1}", cls, klass)
)
try:
obj = klass(**props)
obj.validate()
Expand All @@ -170,6 +170,7 @@ def __new__(cls, **props):
return obj

def __init__(self, **props):
logger.debug(util.lazy_format("Creating '{0}'", self.__class__))
self._extended_properties = dict()
self._properties = dict(
zip(
Expand Down Expand Up @@ -648,6 +649,14 @@ def _build_object(self, nm, clsdata, parents, **kw):

# Set default value, even if None
if "default" in detail:
logger.debug(
util.lazy_format(
"Setting default for {0}.{1} to: {2}",
nm,
prop,
detail["default"],
)
)
defaults.add(prop)

if detail.get("type", None) == "object":
Expand Down
22 changes: 8 additions & 14 deletions python_jsonschema_objects/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,15 @@ class ProtocolJSONEncoder(json.JSONEncoder):
def default(self, obj):
from python_jsonschema_objects import classbuilder, wrapper_types

if isinstance(obj, classbuilder.LiteralValue):
return obj._value
if isinstance(obj, wrapper_types.ArrayWrapper):
if isinstance(
obj,
(
wrapper_types.ArrayWrapper,
classbuilder.ProtocolBase,
classbuilder.LiteralValue,
),
):
return obj.for_json()
if isinstance(obj, classbuilder.ProtocolBase):
props = {}
for raw, trans in six.iteritems(obj.__prop_names__):
props[raw] = getattr(obj, trans)
if props[raw] is None:
del props[raw]
for raw, data in six.iteritems(obj._extended_properties):
props[raw] = data
if props[raw] is None:
del props[raw]
return props
else:
return json.JSONEncoder.default(self, obj)

Expand Down
57 changes: 57 additions & 0 deletions test/test_regression_218.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import pytest
import json
import python_jsonschema_objects as pjo

import logging

logging.basicConfig(level=logging.DEBUG)
logging.getLogger().setLevel(logging.DEBUG)

schema = """
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "schema.json",
"title":"Null Test",
"type": "object",
"$ref": "#/definitions/test",
"definitions": {
"test": {
"type": "object",
"properties": {
"name": {
"type": "string",
"default": "String"
},
"id": {
"type": "null",
"default": null
}
}
}
}
}
"""


@pytest.fixture
def schema_json():
return json.loads(schema)


@pytest.fixture
def ns(schema_json):
builder = pjo.ObjectBuilder(schema_json)
ns = builder.build_classes()
return ns


def test_defaults_serialize_for_nullable_types(ns):
logging.basicConfig(level=logging.DEBUG)
logging.getLogger().setLevel(logging.DEBUG)
thing1 = ns.NullTest()

serialized = thing1.as_dict()
print(serialized)
assert json.dumps(serialized) == """{"name": "String", "id": null}"""
serialized = thing1.serialize()
assert serialized == """{"name": "String", "id": null}"""

0 comments on commit 82b1fb4

Please sign in to comment.