Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Int default for float field causes avro_schema_to_python() to crash #457

Closed
ghost opened this issue Oct 24, 2023 · 0 comments
Closed

Int default for float field causes avro_schema_to_python() to crash #457

ghost opened this issue Oct 24, 2023 · 0 comments

Comments

@ghost
Copy link

ghost commented Oct 24, 2023

Describe the bug

If you use an integer as the default value for a field declared as a float, avro_schema_to_python() will crash.

The problem here is that int is not a subclass of float, which is why this check fails. One way to fix this would be to make a special exception and say "if the field's type is a subclass of numbers.Real then allow an integer".

We could change this:

assert isinstance(default, a_type), msg

to something like:

assert isinstance(default, a_type) or (
    issubclass(a_type, numbers.Real)
    and isinstance(default, numbers.Integral)
    and not isinstance(default, bool)
), msg

(bool is a subclass of int which is why we need that last check.)

To Reproduce

from dataclasses import dataclass
from dataclasses_avroschema import AvroModel

@dataclass
class A(AvroModel):
    number: float = 0

# This will crash
A.avro_schema_to_python()

@dataclass
class B(AvroModel):
    number: float = 0.0

# This works fine
B.avro_schema_to_python()

Stack trace:

[ERROR] AssertionError: Invalid default type <class 'int'> for field "inbound_average_talking_duration". Default should be <class 'float'>
Traceback (most recent call last):
  [. . . .]
  File "/var/task/sns_listeners/avro.py", line 107, in serialize_records_to_s3
    schema = model_class.avro_schema_to_python()
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/schema_generator.py", line 90, in avro_schema_to_python
    avro_schema = cls.generate_schema(schema_type=AVRO)
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/schema_generator.py", line 55, in generate_schema
    cls._rendered_schema = cls._parser.render()
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/parser.py", line 92, in render
    ("fields", self.get_rendered_fields()),
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/parser.py", line 85, in get_rendered_fields
    return [field.render() for field in self.fields]
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/parser.py", line 85, in <listcomp>
    return [field.render() for field in self.fields]
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/fields/base.py", line 75, in render
    template = OrderedDict(self.get_metadata() + [("name", self.name), ("type", self.get_avro_type())])
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/fields/fields.py", line 311, in get_avro_type
    self.unions = self.generate_unions_type()
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/fields/fields.py", line 302, in generate_unions_type
    avro_type = field.get_avro_type()
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/fields/fields.py", line 736, in get_avro_type
    record_type = self.type.avro_schema_to_python(parent=self.parent)
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/schema_generator.py", line 90, in avro_schema_to_python
    avro_schema = cls.generate_schema(schema_type=AVRO)
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/schema_generator.py", line 55, in generate_schema
    cls._rendered_schema = cls._parser.render()
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/parser.py", line 92, in render
    ("fields", self.get_rendered_fields()),
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/parser.py", line 85, in get_rendered_fields
    return [field.render() for field in self.fields]
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/parser.py", line 85, in <listcomp>
    return [field.render() for field in self.fields]
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/fields/base.py", line 80, in render
    self.validate_default(default)
  File "/var/lang/lib/python3.11/site-packages/dataclasses_avroschema/fields/base.py", line 100, in validate_default
    assert isinstance(default, a_type), msg

Expected behavior

In the example above, A.avro_schema_to_python() should not crash, instead returning an equivalent (if not identical) schema to the one returned by B.avro_schema_to_python()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

0 participants