s-knibbs / dataclasses-jsonschema

JSON schema generation from dataclasses
MIT License
166 stars 38 forks source link

RecursionError when creating new field #128

Open elvinlemmens opened 4 years ago

elvinlemmens commented 4 years ago

Hi, I wanted to create a new type of field, similar setup to UUID, but for version numbers. This was my attempt:

import uuid
from dataclasses import dataclass,field
from dataclasses_jsonschema import JsonSchemaMixin,SchemaType,FieldEncoder
from pkg_resources.extern.packaging.version import Version
from pkg_resources import parse_version
from uuid import UUID

class VersionField(FieldEncoder[Version, str]):
    def to_wire(self, value:Version) -> str:
        return value.public

    def to_python(self, value: str) -> Version:
        return value if isinstance(value, Version) else parse_version(value)

    @property
    def json_schema(self):
        return {"type": "string"}

JsonSchemaMixin.register_field_encoders({Version: VersionField()})

@dataclass
class Schema(JsonSchemaMixin):
    Version: Version = field(init=False,default=parse_version('0.0.0'))
    Guid: UUID = field(init=False,default_factory=uuid.uuid4)

JsonSchemaMixin.all_json_schemas(schema_type=SchemaType.SWAGGER_V3)

However when creating the schemas, I get this response:

Traceback (most recent call last):
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\dataclasses_jsonschema\__init__.py", line 277, in _encode_field
    encoder = cls.__encode_cache[field_type]  # type: ignore
KeyError: <unprintable KeyError object>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\dataclasses_jsonschema\__init__.py", line 826, in _get_field_type_name
    return field_type.__name__
AttributeError: 'Field' object has no attribute '__name__'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\IPython\core\interactiveshell.py", line 3296, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-11-1236ba329d3a>", line 27, in <module>
    JsonSchemaMixin.all_json_schemas(schema_type=SchemaType.SWAGGER_V3)
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\dataclasses_jsonschema\__init__.py", line 714, in all_json_schemas
    subclass.json_schema(embeddable=True, schema_type=schema_type, validate_enums=validate_enums)
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\dataclasses_jsonschema\__init__.py", line 761, in json_schema
    properties[f.mapped_name], is_required = cls._get_field_schema(f.field, schema_options)
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\dataclasses_jsonschema\__init__.py", line 600, in _get_field_schema
    field_meta, required = cls._get_field_meta(field, schema_options.schema_type)
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\dataclasses_jsonschema\__init__.py", line 573, in _get_field_meta
    field_meta.default = cls._encode_field(field.type, default_value, omit_none=False)
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\dataclasses_jsonschema\__init__.py", line 281, in _encode_field
    field_type_name = cls._get_field_type_name(field_type)
  File "C:\Users\Elvin Lemmens\virutalenvs\notebooks\lib\site-packages\dataclasses_jsonschema\__init__.py", line 829, in _get_field_type_name
    match = re.match(r'typing\.([A-Za-z]+)', str(field_type))
  File "C:\Users\Elvin Lemmens\AppData\Local\Programs\Python\Python37\lib\dataclasses.py", line 245, in __repr__
    return ('Field('
  File "C:\Users\Elvin Lemmens\AppData\Local\Programs\Python\Python37\lib\dataclasses.py", line 245, in __repr__
    return ('Field('
  File "C:\Users\Elvin Lemmens\AppData\Local\Programs\Python\Python37\lib\dataclasses.py", line 245, in __repr__
    return ('Field('
  [Previous line repeated 1485 more times]
RecursionError: maximum recursion depth exceeded while getting the repr of an object

Any idea? I'm able to bypass it by creating a custom method custom_field instead of field that creates a new CustomField instead of Field from the dataclasses module, which is just a subclass with a fixed repr instead of it being varially built. I'm wondering if this is a bug in the dataclasses library (maybe updating the python version will help, will check), a bug in the dataclasses-json library (incorrect usage of the repr on dataclasses Field's, or just a bug in myself (likely) Regards, Elvin