Skip to content

Bug: Nested Pydantic Models - Unsupported type: 'JsonValue' on field '' from class (2.22.1) #733

@ajstewart

Description

@ajstewart

Description

I have come across another issue with the JsonValue field in pydantic factories and pydantic that was working previously, and has probably been introduced with the attempt to fix a previous issue I had in #725.

It is for situations like that attached where the JsonValue is used in a nested manner. It works ok if it is not nested.

It works for the previous minor version of pydantic:

Pydantic Version Polyfactory Version Result
2.11.7 2.22.1 FAIL
2.11.7 2.22.0 OK
2.11.7 2.21.0 OK
2.10.6 2.22.1 OK
2.10.6 2.22.0 OK
2.10.6 2.21.0 OK

URL to code causing the issue

No response

MCVE

from polyfactory.factories.pydantic_factory import ModelFactory
from pydantic import BaseModel, JsonValue

class Bar(BaseModel):
    a: dict[str, JsonValue]

class Foo(BaseModel):
    b: int
    c: Bar

class FooFactory(ModelFactory[Foo]): ...

test = FooFactory.build()

Steps to reproduce

Run the attached example with Pydantic 2.11.7 and Polyfactory 2.22.1

Screenshots

"In the format of: ![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"

Logs

---------------------------------------------------------------------------
ParameterException                        Traceback (most recent call last)
Cell In[3], line 13
      9     c: Bar
     11 class FooFactory(ModelFactory[Foo]): ...
---> 13 test = FooFactory.build()

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/pydantic_factory.py:543, in ModelFactory.build(cls, factory_use_construct, **kwargs)
    537 if "_build_context" not in kwargs:
    538     kwargs["_build_context"] = PydanticBuildContext(
    539         seen_models=set(),
    540         factory_use_construct=factory_use_construct,
    541     )
--> 543 processed_kwargs = cls.process_kwargs(**kwargs)
    545 return cls._create_model(kwargs["_build_context"], **processed_kwargs)

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/base.py:1092, in BaseFactory.process_kwargs(cls, **kwargs)
   1085     result[field_meta.name] = cls._handle_factory_field(
   1086         field_value=field_value,
   1087         field_build_parameters=field_build_parameters,
   1088         build_context=_build_context,
   1089     )
   1090     continue
-> 1092 field_result = cls.get_field_value(
   1093     field_meta,
   1094     field_build_parameters=field_build_parameters,
   1095     build_context=_build_context,
   1096 )
   1097 if field_result is Null:
   1098     continue

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/pydantic_factory.py:516, in ModelFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    514     result = cls.__random__.choice(field_meta.examples)
    515 else:
--> 516     result = super().get_field_value(
    517         field_meta=field_meta, field_build_parameters=field_build_parameters, build_context=build_context
    518     )
    519 return result

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/base.py:808, in BaseFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    805     if not field_build_parameters and unwrapped_annotation in build_context["seen_models"]:
    806         return None if is_optional(field_meta.annotation) else Null
--> 808     return cls._get_or_create_factory(model=unwrapped_annotation).build(
    809         _build_context=build_context,
    810         **(field_build_parameters if isinstance(field_build_parameters, Mapping) else {}),
    811     )
    813 if BaseFactory.is_batch_factory_type(annotation=unwrapped_annotation):
    814     factory = cls._get_or_create_factory(model=field_meta.type_args[0])

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/pydantic_factory.py:543, in ModelFactory.build(cls, factory_use_construct, **kwargs)
    537 if "_build_context" not in kwargs:
    538     kwargs["_build_context"] = PydanticBuildContext(
    539         seen_models=set(),
    540         factory_use_construct=factory_use_construct,
    541     )
--> 543 processed_kwargs = cls.process_kwargs(**kwargs)
    545 return cls._create_model(kwargs["_build_context"], **processed_kwargs)

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/base.py:1092, in BaseFactory.process_kwargs(cls, **kwargs)
   1085     result[field_meta.name] = cls._handle_factory_field(
   1086         field_value=field_value,
   1087         field_build_parameters=field_build_parameters,
   1088         build_context=_build_context,
   1089     )
   1090     continue
-> 1092 field_result = cls.get_field_value(
   1093     field_meta,
   1094     field_build_parameters=field_build_parameters,
   1095     build_context=_build_context,
   1096 )
   1097 if field_result is Null:
   1098     continue

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/pydantic_factory.py:516, in ModelFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    514     result = cls.__random__.choice(field_meta.examples)
    515 else:
--> 516     result = super().get_field_value(
    517         field_meta=field_meta, field_build_parameters=field_build_parameters, build_context=build_context
    518     )
    519 return result

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/base.py:856, in BaseFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    837             return handle_constrained_collection(
    838                 collection_type=collection_type,  # type: ignore[type-var]
    839                 factory=cls,
   (...)    845                 build_context=build_context,
    846             )
    847         return handle_constrained_mapping(
    848             factory=cls,
    849             field_meta=field_meta,
   (...)    853             build_context=build_context,
    854         )
--> 856     return handle_collection_type(
    857         field_meta,
    858         origin,
    859         cls,
    860         field_build_parameters=field_build_parameters,
    861         build_context=build_context,
    862     )
    864 provider_map = cls.get_provider_map()
    865 if provider := (provider_map.get(field_meta.annotation) or provider_map.get(unwrapped_annotation)):

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/value_generators/complex_types.py:51, in handle_collection_type(field_meta, container_type, factory, field_build_parameters, build_context)
     44 for key_field_meta, value_field_meta in cast(
     45     "Iterable[Tuple[FieldMeta, FieldMeta]]",
     46     zip(field_meta.children[::2], field_meta.children[1::2]),
     47 ):
     48     key = factory.get_field_value(
     49         key_field_meta, field_build_parameters=field_build_parameters, build_context=build_context
     50     )
---> 51     value = factory.get_field_value(
     52         value_field_meta, field_build_parameters=field_build_parameters, build_context=build_context
     53     )
     54     container[key] = value
     55 return container

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/pydantic_factory.py:516, in ModelFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    514     result = cls.__random__.choice(field_meta.examples)
    515 else:
--> 516     result = super().get_field_value(
    517         field_meta=field_meta, field_build_parameters=field_build_parameters, build_context=build_context
    518     )
    519 return result

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/base.py:802, in BaseFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    799     if not children:
    800         return None
--> 802     return cls.get_field_value(cls.__random__.choice(children), field_build_parameters, build_context)
    804 if BaseFactory.is_factory_type(annotation=unwrapped_annotation):
    805     if not field_build_parameters and unwrapped_annotation in build_context["seen_models"]:

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/pydantic_factory.py:516, in ModelFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    514     result = cls.__random__.choice(field_meta.examples)
    515 else:
--> 516     result = super().get_field_value(
    517         field_meta=field_meta, field_build_parameters=field_build_parameters, build_context=build_context
    518     )
    519 return result

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/base.py:856, in BaseFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    837             return handle_constrained_collection(
    838                 collection_type=collection_type,  # type: ignore[type-var]
    839                 factory=cls,
   (...)    845                 build_context=build_context,
    846             )
    847         return handle_constrained_mapping(
    848             factory=cls,
    849             field_meta=field_meta,
   (...)    853             build_context=build_context,
    854         )
--> 856     return handle_collection_type(
    857         field_meta,
    858         origin,
    859         cls,
    860         field_build_parameters=field_build_parameters,
    861         build_context=build_context,
    862     )
    864 provider_map = cls.get_provider_map()
    865 if provider := (provider_map.get(field_meta.annotation) or provider_map.get(unwrapped_annotation)):

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/value_generators/complex_types.py:59, in handle_collection_type(field_meta, container_type, factory, field_build_parameters, build_context)
     55     return container
     57 if issubclass(container_type, MutableSequence):
     58     container.extend(
---> 59         [
     60             factory.get_field_value(
     61                 subfield_meta, field_build_parameters=field_build_parameters, build_context=build_context
     62             )
     63             for subfield_meta in field_meta.children
     64         ]
     65     )
     66     return container
     68 if issubclass(container_type, Set):

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/value_generators/complex_types.py:60, in <listcomp>(.0)
     55     return container
     57 if issubclass(container_type, MutableSequence):
     58     container.extend(
     59         [
---> 60             factory.get_field_value(
     61                 subfield_meta, field_build_parameters=field_build_parameters, build_context=build_context
     62             )
     63             for subfield_meta in field_meta.children
     64         ]
     65     )
     66     return container
     68 if issubclass(container_type, Set):

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/pydantic_factory.py:516, in ModelFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    514     result = cls.__random__.choice(field_meta.examples)
    515 else:
--> 516     result = super().get_field_value(
    517         field_meta=field_meta, field_build_parameters=field_build_parameters, build_context=build_context
    518     )
    519 return result

File /opt/homebrew/Caskroom/mambaforge/base/envs/my-env-311/lib/python3.11/site-packages/polyfactory/factories/base.py:882, in BaseFactory.get_field_value(cls, field_meta, field_build_parameters, build_context)
    875         return unwrapped_annotation()
    877 msg = (
    878     f"Unsupported type: {unwrapped_annotation!r} on field '{field_meta.name}' from class {cls.__name__}."
    879     "\n\nEither use 'add_provider', extend the providers map, or add a factory function for the field on the model."
    880 )
--> 882 raise ParameterException(
    883     msg,
    884 )

ParameterException: Unsupported type: 'JsonValue' on field '' from class BarFactory.

Either use 'add_provider', extend the providers map, or add a factory function for the field on the model.

Release Version

2.22.1

Platform

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions