Skip to content
Open
15 changes: 15 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Test

on: [push, pull_request]

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest

steps:
- name: Run pytest
uses: cclauss/[email protected]
29 changes: 23 additions & 6 deletions pykson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,9 +623,7 @@ def __get_fields(cls) -> List[Field]:
fields_list.append(field)
for base in cls.__bases__:
base_type_dicts = base.__dict__ # type(self).__dict__
for n, field in base_type_dicts.items():
if isinstance(field, Field):
fields_list.append(field)
fields_list += JsonObjectMeta.__get_fields(base)
return fields_list

@staticmethod
Expand Down Expand Up @@ -725,18 +723,32 @@ def __init__(self, accept_unknown: bool = False, extra_attributes: Optional[List
# Empty init will be replaced by meta class
super(JsonObject, self).__init__()

def __str__(self):
return json.dumps(json.loads(Pykson().to_json(self)), indent=2, sort_keys=True)

T = TypeVar('T', bound=JsonObject)


class ObjectField(Field):
def __set__(self, instance, value, test: bool = False):
if isinstance(value, dict) and issubclass(self.item_type, JsonObject):
super().__set__(instance, Pykson().from_json(value, self.item_type), test)
return
if value is not None and not isinstance(value, self.item_type):
raise TypeError(instance, self.name, self.item_type, value)
super().__set__(instance, value, test)

def __init__(self, item_type: Type[T], serialized_name: Optional[str] = None, null: bool = True):
super(ObjectField, self).__init__(field_type=FieldType.LIST, serialized_name=serialized_name, null=null)
def __init__(self,
item_type: Type[T],
serialized_name: Optional[str] = None,
null: bool = True,
default_value: Optional[Any] = None):
super(ObjectField, self).__init__(
field_type=FieldType.LIST,
serialized_name=serialized_name,
null=null,
default_value=default_value)
assert default_value is None or isinstance(default_value, JsonObject)
self.item_type = item_type


Expand All @@ -751,6 +763,9 @@ def __set__(self, instance, value, test: bool = False):
value = []
for item in value:
assert item is not None, "Null item passed to ObjectListField"
if not isinstance(item, self.item_type) and isinstance(item, dict) and issubclass(self.item_type, JsonObject):
super(ObjectListField, self).__set__(instance, Pykson().from_json(value, self.item_type), test)
return
assert isinstance(item, self.item_type), "ObjectListField items must be of " + str(
self.item_type) + ", found " + str(type(item))
super(ObjectListField, self).__set__(instance, value, test)
Expand Down Expand Up @@ -1062,7 +1077,9 @@ def _to_json(self, item: Union[T, List[T]], serialized_keys_based: bool = True)
final_dict[field_key] = field_value
return final_dict

def to_json(self, item: Union[T, List[T]]) -> str:
def to_json(self, item: Union[T, List[T]], indent: bool = True) -> str:
if indent:
return json.dumps(self._to_json(item), indent=2, sort_keys=True)
return json.dumps(self._to_json(item))

def to_dict_or_list(self, item: Union[T, List[T]]) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
required = f.read().splitlines()

setuptools.setup(name='pykson',
version='0.9.9.8.7',
author='Sina Rezaei',
author_email='[email protected]',
version='1.0.2',
author='Sina Rezaei, Patrick J. Pereira',
author_email='[email protected], [email protected]',
long_description_content_type="text/markdown",
long_description=long_description,
description='Pykson: A JSON Serializer/Deserializer for Python',
Expand Down
20 changes: 20 additions & 0 deletions test_pykson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import pykson

class Class1(pykson.JsonObject):
variable_1 = pykson.IntegerField(default_value=1)

class Class2(Class1):
variable_2 = pykson.IntegerField(default_value=2)

class Class3(Class2):
variable_3 = pykson.IntegerField(default_value=3)

class Class4(Class3):
variable_4 = pykson.IntegerField(default_value=4)

def test_multiple_inheritance():
class4 = Class4()
assert class4.variable_1 == 1
assert class4.variable_2 == 2
assert class4.variable_3 == 3
assert class4.variable_4 == 4