diff --git a/python_jsonschema_objects/classbuilder.py b/python_jsonschema_objects/classbuilder.py index 9b9a4a2..9ae08c3 100644 --- a/python_jsonschema_objects/classbuilder.py +++ b/python_jsonschema_objects/classbuilder.py @@ -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 @@ -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() @@ -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( @@ -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": diff --git a/python_jsonschema_objects/util.py b/python_jsonschema_objects/util.py index 9c033b3..94eb7a6 100644 --- a/python_jsonschema_objects/util.py +++ b/python_jsonschema_objects/util.py @@ -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) diff --git a/test/test_regression_218.py b/test/test_regression_218.py new file mode 100644 index 0000000..6d0e2a6 --- /dev/null +++ b/test/test_regression_218.py @@ -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}"""