Typing global and local namespace missing objects on function import

Viewed 99

If in the code below we used the import version of the function of create_model_from_dict_hide we get the below namespace error in typing. If however we use a local definition of the function the PyDantic Models are available in both the local and global namespace at line 539 of typing.py

How can we make the models available in the namespace with imported functions

Example code. Copy create_model_from_dict_hide to a file called pydantic_utils to recreate the error

from typing import (
    Any,
    Dict,
    Type,
    cast,
)
import warnings
from pydantic import BaseConfig, ConfigError, BaseModel
from pydantic.utils import is_valid_field
from pydantic.main import inherit_config

from pydantic_utils import create_model_from_dict

import family

def create_model_from_dict_hide(
        __model_name: str,
        *,
        __config__: Type[BaseConfig] = None,
        __base__: Type["Model"] = None,
        __module__: str = __name__,
        __validators__: Dict[str, classmethod] = None,
        **field_definitions: Any,
) -> Type["Model"]:
    """
    Dynamically create a model.
    :param __model_name: name of the created model
    :param __config__: config class to use for the new model
    :param __base__: base class for the new model to inherit from
    :param __module__: module of the created model
    :param __validators__: a dict of method names and @validator class methods
    :param field_definitions: fields of the model (or extra fields if a base is supplied)
        in the format `<name>=(<type>, <default default>)` or `<name>=<default value>, e.g.
        `foobar=(str, ...)` or `foobar=123`, or, for complex use-cases, in the format
        `<name>=<FieldInfo>`, e.g. `foo=Field(default_factory=datetime.utcnow, alias='bar')`
    """

    if __base__ is not None:
        if __config__ is not None:
            raise ConfigError("to avoid confusion __config__ and __base__ cannot be used together")
    else:
        __base__ = cast(Type["Model"], BaseModel)

    fields = {}
    annotations = {}

    for f_name, f_def in field_definitions.items():
        if not is_valid_field(f_name):
            warnings.warn(f'fields may not start with an underscore, ignoring "{f_name}"', RuntimeWarning)

        if "dict" in f_def:
            f_def = f_def.replace("(", "[").replace(")", "]")
        annotations[f_name] = f_def
        fields[f_name] = None

    namespace: "DictStrAny" = {"__annotations__": annotations, "__module__": __module__}
    if __validators__:
        namespace.update(__validators__)
    namespace.update(fields)
    if __config__:
        namespace["Config"] = inherit_config(__config__, BaseConfig)

    return type(__model_name, (__base__,), namespace)

# comment out this line to create the error
create_model_from_dict = create_model_from_dict_hide


Parent = create_model_from_dict("Parent", __config__=BaseConfig, **family.parent)

Child = create_model_from_dict("Child", __config__=BaseConfig, **family.child)

GrandChild = create_model_from_dict("GrandChild", __config__=BaseConfig, **family.grand_child)

GrandChild.update_forward_refs()
Parent.update_forward_refs()
Child.update_forward_refs()

g1 = GrandChild(name='donald jr jr', age=1)
g2 = GrandChild(name='donald jr jr', age=2)
x1 = Child(name='donald jr', age=1, grand_child=g1)
x2 = Child(name='eric', age=1, grand_child=g2)
y = Parent(name='donald', child=x1)


  File "/Users/henry/payaable/fastapp/backend/temp.py", line 74, in <module>
    Parent.update_forward_refs()
  File "pydantic/main.py", line 832, in pydantic.main.BaseModel.update_forward_refs
  File "pydantic/typing.py", line 382, in pydantic.typing.update_field_forward_refs
    
  File "pydantic/typing.py", line 70, in pydantic.typing.evaluate_forwardref
    'Coroutine',
  File "/usr/local/Cellar/python@3.9/3.9.4/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py", line 539, in _evaluate
    eval(self.__forward_code__, globalns, localns),
  File "<string>", line 1, in <module>
NameError: name 'Child' is not defined
0 Answers
Related