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

Bug: build fails if max_length constraint set with scientific notation #621

Open
1 of 4 tasks
ollyhensby opened this issue Dec 11, 2024 · 1 comment
Open
1 of 4 tasks
Labels
bug Something isn't working

Comments

@ollyhensby
Copy link

ollyhensby commented Dec 11, 2024

Description

I set max_length to 1e3 and the build method fails.

The bug seems to have been introduced when python>=3.12.

URL to code causing the issue

No response

MCVE

import typing as ty
from pydantic import BaseModel, Field
from polyfactory.factories.pydantic_factory import ModelFactory

class Test(BaseModel):
    notes: str = Field(
        "",
        max_length=1e3,
    )

class TestFactory(ModelFactory[Test]):
    __model__ = Test


TestFactory.build()

Steps to reproduce

1. Run the above code.
2. See error.

Screenshots

No response

Logs

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/factories/base.py:614, in BaseFactory.get_constrained_field_value(cls, annotation, field_meta, field_build_parameters, build_context)
    613 if is_safe_subclass(annotation, str) or is_safe_subclass(annotation, bytes):
--> 614     return handle_constrained_string_or_bytes(
    615         random=cls.__random__,
    616         t_type=str if is_safe_subclass(annotation, str) else bytes,
    617         lower_case=constraints.get("lower_case") or False,
    618         upper_case=constraints.get("upper_case") or False,
    619         min_length=constraints.get("min_length"),
    620         max_length=constraints.get("max_length"),
    621         pattern=constraints.get("pattern"),
    622     )
    624 try:

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/value_generators/constrained_strings.py:120, in handle_constrained_string_or_bytes(random, t_type, lower_case, upper_case, min_length, max_length, pattern)
    117 if t_type is str:
    118     return cast(
    119         "T",
--> 120         create_random_string(
    121             min_length=min_length,
    122             max_length=max_length,
    123             lower_case=lower_case,
    124             upper_case=upper_case,
    125             random=random,
    126         ),
    127     )
    129 return cast(
    130     "T",
    131     create_random_bytes(
   (...)
    137     ),
    138 )

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/value_generators/primitives.py:113, in create_random_string(random, min_length, max_length, lower_case, upper_case)
    103 """Generate a random string given the constraints.
    104 
    105 :param random: An instance of random.
   (...)
    111 :returns: A random string.
    112 """
--> 113 return create_random_bytes(
    114     random=random,
    115     min_length=min_length,
    116     max_length=max_length,
    117     lower_case=lower_case,
    118     upper_case=upper_case,
    119 ).decode("utf-8")

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/value_generators/primitives.py:81, in create_random_bytes(random, min_length, max_length, lower_case, upper_case)
     79     max_length = min_length + 1 * 2
---> 81 length = random.randint(min_length, max_length)
     82 result = b"" if length == 0 else hexlify(random.getrandbits(length * 8).to_bytes(length, "little"))

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/random.py:340, in Random.randint(self, a, b)
    337 """Return random integer in range [a, b], including both end points.
    338 """
--> 340 return self.randrange(a, b+1)

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/random.py:316, in Random.randrange(self, start, stop, step)
    315 # Stop argument supplied.
--> 316 istop = _index(stop)
    317 width = istop - istart

TypeError: 'float' object cannot be interpreted as an integer

The above exception was the direct cause of the following exception:

ParameterException                        Traceback (most recent call last)
Cell In[8], line 15
     11 class TestFactory(ModelFactory[Test]):
     12     __model__ = Test
---> 15 TestFactory.build()

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/factories/pydantic_factory.py:473, in ModelFactory.build(cls, factory_use_construct, **kwargs)
    468 if "_build_context" not in kwargs:
    469     kwargs["_build_context"] = PydanticBuildContext(
    470         seen_models=set(), factory_use_construct=factory_use_construct
    471     )
--> 473 processed_kwargs = cls.process_kwargs(**kwargs)
    475 return cls._create_model(kwargs["_build_context"], **processed_kwargs)

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/factories/base.py:1003, in BaseFactory.process_kwargs(cls, **kwargs)
    996     result[field_meta.name] = cls._handle_factory_field(
    997         field_value=field_value,
    998         field_build_parameters=field_build_parameters,
    999         build_context=_build_context,
   1000     )
   1001     continue
-> 1003 field_result = cls.get_field_value(
   1004     field_meta,
   1005     field_build_parameters=field_build_parameters,
   1006     build_context=_build_context,
   1007 )
   1008 if field_result is Null:
   1009     continue

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/factories/base.py:706, in BaseFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    703     return cls.__random__.choice(list(unwrapped_annotation))
    705 if field_meta.constraints:
--> 706     return cls.get_constrained_field_value(
    707         annotation=unwrapped_annotation,
    708         field_meta=field_meta,
    709         field_build_parameters=field_build_parameters,
    710         build_context=build_context,
    711     )
    713 if is_union(field_meta.annotation) and field_meta.children:
    714     seen_models = build_context["seen_models"]

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/factories/pydantic_factory.py:448, in ModelFactory.get_constrained_field_value(cls, annotation, field_meta, field_build_parameters, build_context)
    443     value = cls.get_field_value(
    444         field_meta, field_build_parameters=field_build_parameters, build_context=build_context
    445     )
    446     return to_json(value)  # pyright: ignore[reportPossiblyUnboundVariable]
--> 448 return super().get_constrained_field_value(
    449     annotation, field_meta, field_build_parameters=field_build_parameters, build_context=build_context
    450 )

File ~/miniforge3/envs/polyfactory-test/lib/python3.13/site-packages/polyfactory/factories/base.py:669, in BaseFactory.get_constrained_field_value(cls, annotation, field_meta, field_build_parameters, build_context)
    667         return handle_constrained_path(constraint=path_constraint, faker=cls.__faker__)
    668 except TypeError as e:
--> 669     raise ParameterException from e
    671 msg = f"received constraints for unsupported type {annotation}"
    672 raise ParameterException(msg)

ParameterException:

Release Version

polyfactory: 2.18.1
python: 3.13.1

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Note

While we are open for sponsoring on GitHub Sponsors and
OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.

Check out all issues funded or available for funding on our Polar.sh dashboard

  • If you would like to see an issue prioritized, make a pledge towards it!
  • We receive the pledge once the issue is completed & verified
  • This, along with engagement in the community, helps us know which features are a priority to our users.
Fund with Polar
@ollyhensby ollyhensby added the bug Something isn't working label Dec 11, 2024
@ollyhensby
Copy link
Author

I understand that this could just be resolved by using 1000 instead of 1e3 but I feel scientific notation should be supported as it was working with python==3.11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant