def main(): Foo = ForwardRef('Foo') class Foo(BaseModel): a: int = 123 b: Foo = None Foo.update_forward_refs() return Foo
def module(): from pydantic import BaseModel from pydantic.typing import ForwardRef Foo = ForwardRef('Foo') class Foo(BaseModel): a: int = 123 b: 'Foo' = None Foo.update_forward_refs()
def module(): from typing import Dict, List from pydantic import BaseModel from pydantic.typing import ForwardRef Foo = ForwardRef('Foo') class Foo(BaseModel): a: int = 123 b: Foo = None c: List[Foo] = [] d: Dict[str, Foo] = {} Foo.update_forward_refs()
async def test_not_updated_model_m2m_raises_errors(): Person3Ref = ForwardRef("Person3") class PersonFriend(ormar.Model): class Meta(ModelMeta): metadata = metadata database = db class Person3(ormar.Model): class Meta(ModelMeta): metadata = metadata database = db id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) supervisors: Person3Ref = ormar.ManyToMany(Person3Ref, through=PersonFriend, related_name="employees") with pytest.raises(ModelError): await Person3.objects.create(name="Test") with pytest.raises(ModelError): Person3(name="Test") with pytest.raises(ModelError): await Person3.objects.get()
async def test_not_updated_model_m2m_through_raises_errors(): PersonPetRef = ForwardRef("PersonPet") class Pet(ormar.Model): class Meta(ModelMeta): metadata = metadata database = db id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Person4(ormar.Model): class Meta(ModelMeta): metadata = metadata database = db id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) pets: List[Pet] = ormar.ManyToMany(Pet, through=PersonPetRef, related_name="owners") class PersonPet(ormar.Model): class Meta(ModelMeta): metadata = metadata database = db with pytest.raises(ModelError): await Person4.objects.create(name="Test") with pytest.raises(ModelError): Person4(name="Test") with pytest.raises(ModelError): await Person4.objects.get()
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: annotation = param.annotation if isinstance(annotation, str): annotation = ForwardRef(annotation) annotation = evaluate_forwardref(annotation, globalns, globalns) return annotation
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: annotation = param.annotation if isinstance(annotation, str): # Temporary ignore type # Ref: https://github.com/samuelcolvin/pydantic/issues/1738 annotation = ForwardRef(annotation) # type: ignore annotation = evaluate_forwardref(annotation, globalns, globalns) return annotation
class Post2(ormar.Model): class Meta(BaseMeta): pass id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) categories = ormar.ManyToMany(Category, through=ForwardRef("PostCategory2"))
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: annotation = param.annotation if isinstance(annotation, str): try: annotation = ForwardRef(annotation) # type: ignore annotation = evaluate_forwardref(annotation, globalns, globalns) except (TypeError, NameError): annotation = param.annotation return annotation
def module(): from pydantic import BaseModel from pydantic.typing import ForwardRef Foo = ForwardRef('Foo') class Foo(BaseModel): a: int = 123 b: Foo = None
def test_forward_ref_one_of_fields_not_defined(create_module): @create_module def module(): from pydantic import BaseModel class Foo(BaseModel): foo: 'Foo' bar: 'Bar' # noqa: F821 from pydantic.typing import ForwardRef assert module.Foo.__fields__['bar'].type_ == ForwardRef('Bar') assert module.Foo.__fields__['foo'].type_ is module.Foo
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: annotation = param.annotation if isinstance(annotation, str): annotation = ForwardRef(annotation) try: annotation = evaluate_forwardref(annotation, globalns, globalns) except Exception as e: logger.opt(colors=True, exception=e).warning( f'Unknown ForwardRef["{param.annotation}"] for parameter {param.name}' ) return inspect.Parameter.empty return annotation
def module(): from typing import Optional from pydantic import BaseModel from pydantic.typing import ForwardRef class Foo(BaseModel): a: int FooRef = ForwardRef('Foo') class Bar(BaseModel): b: Optional[FooRef]
def module(): from typing import List import pytest from pydantic import BaseModel, Field from pydantic.typing import ForwardRef Foo = ForwardRef('Foo') with pytest.raises( ValueError, match='On field "c" the following field constraints are set but not enforced: gt.' ): class Foo(BaseModel): c: List[Foo] = Field(..., gt=0)
def module(): from typing import Tuple, Union from pydantic import BaseModel from pydantic.typing import ForwardRef class Leaf(BaseModel): a: str TreeType = Union[Union[Tuple[ForwardRef('Node'), str], int], Leaf] class Node(BaseModel): value: int left: TreeType right: TreeType Node.update_forward_refs()
def test_forward_ref_auto_update_no_model(create_module): module = create_module( # language=Python """ from pydantic import BaseModel class Foo(BaseModel): a: 'Bar' class Bar(BaseModel): b: 'Foo' """) from pydantic.typing import ForwardRef assert module.Foo.__fields__['a'].type_ == ForwardRef('Bar') assert module.Bar.__fields__['b'].type_ is module.Foo
def get_typed_annotation( dependency_param: inspect.Parameter, global_namespace: Dict[str, Any], ) -> Any: """Solve forward reference annotation for instance of `inspect.Parameter`. Arguments: dependency_param: instance of `inspect.Parameter` for which possible forward annotation will be evaluated. global_namespace: dictionary of entities that can be used for evaluating forward references. Returns: Parameter annotation. """ annotation = dependency_param.annotation if isinstance(annotation, str): annotation = ForwardRef(annotation) annotation = evaluate_forwardref(annotation, global_namespace, global_namespace) return annotation
async def test_not_updated_model_raises_errors(): Person2Ref = ForwardRef("Person2") class Person2(ormar.Model): class Meta(ModelMeta): metadata = metadata database = db id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) supervisor: Person2Ref = ormar.ForeignKey(Person2Ref, related_name="employees") with pytest.raises(ModelError): await Person2.objects.create(name="Test") with pytest.raises(ModelError): Person2(name="Test") with pytest.raises(ModelError): await Person2.objects.get()
# nested decorator should not produce an error @validate_arguments(config={'arbitrary_types_allowed': True}) def bar(a: int, *, c: str = 'x') -> str: return c * a bar(1, c='thing') bar(1) class Foo(BaseModel): a: int FooRef = ForwardRef('Foo') class MyConf(BaseModel): str_pyobject: PyObject = Field('datetime.date') callable_pyobject: PyObject = Field(date) conf = MyConf() var1: date = conf.str_pyobject(2020, 12, 20) var2: date = conf.callable_pyobject(2111, 1, 1) class MyPrivateAttr(BaseModel): _private_field: str = PrivateAttr()
def make_forwardref(annotation: str, globalns: Dict[str, Any]): annotation = ForwardRef(annotation) annotation = evaluate_forwardref(annotation, globalns, globalns) return annotation
import databases import pytest import sqlalchemy as sa from pydantic.typing import ForwardRef from sqlalchemy import create_engine import ormar from ormar import ModelMeta from tests.settings import DATABASE_URL metadata = sa.MetaData() db = databases.Database(DATABASE_URL) engine = create_engine(DATABASE_URL) TeacherRef = ForwardRef("Teacher") class Student(ormar.Model): class Meta(ModelMeta): metadata = metadata database = db id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) primary_teacher: TeacherRef = ormar.ForeignKey(TeacherRef, related_name="own_students") class StudentTeacher(ormar.Model): class Meta(ModelMeta):
class FieldPropertyWithDstId(BaseModel): datasheetId: str field: ForwardRef("MetaField")
def make_forwardref(annotation: str, globalns: DictStrAny) -> Any: forward_ref = ForwardRef(annotation) return evaluate_forwardref(forward_ref, globalns, globalns)
def _extract_relations( mapper: Mapper, fields: Dict, reverse: bool, metadata: MetaData, database: Database, db_model: Type, ) -> Dict: for attr in mapper.attrs: # type: ignore if isinstance(attr, sqlalchemy.orm.RelationshipProperty): # skip one to many, it will be populated later by ormar # if attr.direction.name == "ONETOMANY": # continue if attr.direction.name == "MANYTOONE": # we use forward ref as target might not be populated target_sqlalchemy = attr.entity.class_ if ( target_sqlalchemy not in PARSED_MODELS and target_sqlalchemy not in CURRENTLY_PROCESSED and not target_sqlalchemy == db_model ): PARSED_MODELS[target_sqlalchemy] = sqlalchemy_to_ormar( target_sqlalchemy, metadata=metadata, database=database ) target = PARSED_MODELS[target_sqlalchemy] else: target = ForwardRef(target_sqlalchemy.__name__) # type: ignore column = next(iter(attr.local_columns)) sql_fk = next(iter(column.foreign_keys)) fields[attr.key] = dict( type=ormar.ForeignKey, to=target, name=column.key, related_name=attr.back_populates, onupdate=getattr(sql_fk, "onupdate", None), ondelete=getattr(sql_fk, "ondelete", None), ) elif attr.direction.name == "MANYTOMANY": target_sqlalchemy = attr.entity.class_ if target_sqlalchemy not in PARSED_MODELS and not reverse: PARSED_MODELS[target_sqlalchemy] = sqlalchemy_to_ormar( target_sqlalchemy, metadata=metadata, database=database, reverse=True, ) else: # pragma: no cover # target model already should have m2m relation continue target = PARSED_MODELS[target_sqlalchemy] through_table_name = attr.secondary.key fields[attr.key] = dict( type=ormar.ManyToMany, to=target, through=create_through_model( class_name=through_table_name.title(), table_name=through_table_name, metadata=metadata, database=database, ), related_name=attr.back_populates, ) return fields
def test_resolve_annotations_no_module(): # TODO: is there a better test for this, can this case really happen? fr = ForwardRef('Foo') assert resolve_annotations({'Foo': ForwardRef('Foo')}, None) == {'Foo': fr}
import databases import pytest import sqlalchemy as sa from pydantic.typing import ForwardRef from sqlalchemy import create_engine import ormar from ormar import ModelMeta from ormar.exceptions import ModelError from tests.settings import DATABASE_URL metadata = sa.MetaData() db = databases.Database(DATABASE_URL) engine = create_engine(DATABASE_URL) PersonRef = ForwardRef("Person") class Person(ormar.Model): class Meta(ModelMeta): metadata = metadata database = db id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) supervisor: PersonRef = ormar.ForeignKey(PersonRef, related_name="employees") Person.update_forward_refs()