biqqles / dataclassy

A fast and flexible reimplementation of data classes
https://pypi.org/project/dataclassy
Mozilla Public License 2.0
81 stars 9 forks source link

__dataclass_fields__ is missing #37

Closed ZdenekM closed 3 years ago

ZdenekM commented 3 years ago

I just found dataclassy and it looks really useful! I wanted to test it together with https://github.com/s-knibbs/dataclasses-jsonschema which I'm using in one of my projects, but got this:

>>> from dataclassy import dataclass
>>> from dataclasses_jsonschema import JsonSchemaMixin
>>> @dataclass
... class Item(JsonSchemaMixin):
...     id: str = ""
... 
>>> it=Item()
>>> it.to_json()
Traceback (most recent call last):
  File "/usr/lib/python3.8/dataclasses.py", line 1031, in fields
    fields = getattr(class_or_instance, _FIELDS)
AttributeError: type object 'Item' has no attribute '__dataclass_fields__'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/zdenal/arcor2_repos/arcor2/build-support/.venv/lib/python3.8/site-packages/dataclasses_jsonschema/__init__.py", line 861, in to_json
    return json.dumps(self.to_dict(omit_none, validate), **json_kwargs)
  File "/home/zdenal/arcor2_repos/arcor2/build-support/.venv/lib/python3.8/site-packages/dataclasses_jsonschema/__init__.py", line 389, in to_dict
    for f in self._get_fields():
  File "/home/zdenal/arcor2_repos/arcor2/build-support/.venv/lib/python3.8/site-packages/dataclasses_jsonschema/__init__.py", line 380, in _get_fields
    cls.__mapped_fields = _get_fields_uncached()
  File "/home/zdenal/arcor2_repos/arcor2/build-support/.venv/lib/python3.8/site-packages/dataclasses_jsonschema/__init__.py", line 353, in _get_fields_uncached
    for f in fields(cls):
  File "/usr/lib/python3.8/dataclasses.py", line 1033, in fields
    raise TypeError('must be called with a dataclass type or instance')
TypeError: must be called with a dataclass type or instance

Would it be possible to add/emulate __dataclass_fields__ to make these two compatible?

biqqles commented 3 years ago

Hmm, the fact that this error is raised inside dataclasses makes me suspicious that this will not be the only problem. Also, it originates in a call to fields() which in dataclasses returns a dict with Field instances as values, a class which dataclassy does not have.

If you wanted to test whether it is really as simple as setting __dataclass_fields__, you could try setting

from dataclassy import fields

Item.__dataclass_fields__ = fields(Item)

But I am not hopeful. I think a better way to consider would be monkey-patching _get_fields. This seems like it might be quite easy since dataclassy already does a lot of the work for you - its fields() automatically removes internal fields and includes the type annotations in the result.

ZdenekM commented 3 years ago

You were right, __dataclass_fields__ was not the problem. When I set it, I got:

>>> Item.__dataclass_fields__ = fields(Item)
>>> 
>>> it.to_json()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/zdenal/arcor2_repos/arcor2/build-support/.venv/lib/python3.8/site-packages/dataclasses_jsonschema/__init__.py", line 862, in to_json
    return json.dumps(self.to_dict(omit_none, validate), **json_kwargs)
  File "/home/zdenal/arcor2_repos/arcor2/build-support/.venv/lib/python3.8/site-packages/dataclasses_jsonschema/__init__.py", line 390, in to_dict
    for f in self._get_fields():
  File "/home/zdenal/arcor2_repos/arcor2/build-support/.venv/lib/python3.8/site-packages/dataclasses_jsonschema/__init__.py", line 381, in _get_fields
    cls.__mapped_fields = _get_fields_uncached()
  File "/home/zdenal/arcor2_repos/arcor2/build-support/.venv/lib/python3.8/site-packages/dataclasses_jsonschema/__init__.py", line 354, in _get_fields_uncached
    for f in fields(cls):
  File "/usr/lib/python3.8/dataclasses.py", line 1037, in fields
    return tuple(f for f in fields.values() if f._field_type is _FIELD)
  File "/usr/lib/python3.8/dataclasses.py", line 1037, in <genexpr>
    return tuple(f for f in fields.values() if f._field_type is _FIELD)
AttributeError: type object 'str' has no attribute '_field_type'

Thank you for the tip to monkey-patch the _get_fields - I will try it.

biqqles commented 3 years ago

Any luck with the patching? Or any more suggestions for dataclassy to make it easier? Otherwise I'll close this.