From 31f9a647e3330d319be7feae2a287284b7298970 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 19 Sep 2023 09:42:39 +0200 Subject: [PATCH 01/95] WIP --- docs_src/models/docs003.py | 6 +- ormar/fields/base.py | 14 +- ormar/fields/foreign_key.py | 6 +- ormar/fields/many_to_many.py | 7 +- ormar/fields/parsers.py | 9 +- ormar/models/helpers/models.py | 2 +- ormar/models/helpers/pydantic.py | 37 +- .../helpers/related_names_validation.py | 2 +- ormar/models/helpers/sqlalchemy.py | 2 +- ormar/models/helpers/validation.py | 23 +- ormar/models/metaclass.py | 2 +- ormar/models/mixins/pydantic_mixin.py | 4 +- ormar/models/mixins/save_mixin.py | 2 +- poetry.lock | 368 ++++++++++++++---- pyproject.toml | 4 +- tests/test_types.py | 30 +- 16 files changed, 366 insertions(+), 152 deletions(-) diff --git a/docs_src/models/docs003.py b/docs_src/models/docs003.py index e79bfba25..38b4763ad 100644 --- a/docs_src/models/docs003.py +++ b/docs_src/models/docs003.py @@ -20,15 +20,15 @@ class Meta: print(Course.__fields__) """ Will produce: -{'id': ModelField(name='id', +{'id': Field(name='id', type=Optional[int], required=False, default=None), - 'name': ModelField(name='name', + 'name': Field(name='name', type=Optional[str], required=False, default=None), -'completed': ModelField(name='completed', +'completed': Field(name='completed', type=bool, required=False, default=False)} diff --git a/ormar/fields/base.py b/ormar/fields/base.py index f7eaff5c5..cb320cf6d 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -2,8 +2,8 @@ from typing import Any, Dict, List, Optional, TYPE_CHECKING, Type, Union import sqlalchemy -from pydantic import Json, typing -from pydantic.fields import FieldInfo, Required, Undefined +from pydantic import typing +from pydantic.fields import FieldInfo, _Undefined import ormar # noqa I101 from ormar import ModelDefinitionError @@ -145,9 +145,7 @@ def get_pydantic_default(self) -> Dict: """ base = self.default_value() if base is None: - base = dict(default=None) if self.nullable else dict(default=Undefined) - if self.__type__ == Json and base.get("default") is Undefined: - base["default"] = Required + base = dict(default=None) if self.nullable else dict(default=_Undefined) return base def default_value(self, use_server: bool = False) -> Optional[Dict]: @@ -181,7 +179,9 @@ def default_value(self, use_server: bool = False) -> Optional[Dict]: return dict(default=default) return None - def get_default(self, use_server: bool = False) -> Any: # noqa CCR001 + def get_default( + self, use_server: bool = False, call_default_factory: bool = True + ) -> Any: # noqa CCR001 """ Return default value for a field. If the field is Callable the function is called and actual result is returned. @@ -199,7 +199,7 @@ def get_default(self, use_server: bool = False) -> Any: # noqa CCR001 if self.ormar_default is not None else (self.server_default if use_server else None) ) - if callable(default): # pragma: no cover + if callable(default) and call_default_factory: # pragma: no cover default = default() return default diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index cfa2205ba..102597b14 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -5,6 +5,7 @@ from typing import ( Any, Dict, + ForwardRef, List, Optional, TYPE_CHECKING, @@ -14,13 +15,14 @@ overload, ) +from pydantic._internal._typing_extra import evaluate_fwd_ref + import ormar # noqa I101 import sqlalchemy from ormar.exceptions import ModelDefinitionError, RelationshipInstanceError from ormar.fields.base import BaseField from ormar.fields.referential_actions import ReferentialAction from pydantic import BaseModel, create_model -from pydantic.typing import ForwardRef, evaluate_forwardref if TYPE_CHECKING: # pragma no cover from ormar.models import Model, NewBaseModel, T @@ -364,7 +366,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = evaluate_forwardref( + self.to = evaluate_fwd_ref( self.to, globalns, localns or None # type: ignore ) ( diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 350fa3c38..e69bfdcd6 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -1,6 +1,7 @@ import sys from typing import ( Any, + ForwardRef, List, Optional, TYPE_CHECKING, @@ -11,7 +12,7 @@ overload, ) -from pydantic.typing import ForwardRef, evaluate_forwardref +from pydantic._internal._typing_extra import evaluate_fwd_ref import ormar # noqa: I100 from ormar import ModelDefinitionError from ormar.fields import BaseField @@ -222,7 +223,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = evaluate_forwardref( + self.to = evaluate_fwd_ref( self.to, globalns, localns or None # type: ignore ) @@ -231,7 +232,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: ) if self.through.__class__ == ForwardRef: - self.through = evaluate_forwardref( + self.through = evaluate_fwd_ref( self.through, globalns, localns or None # type: ignore ) forbid_through_relations(self.through) diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index c3d85febb..31fb22821 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -5,7 +5,7 @@ from typing import Any, Callable, Dict, Optional, Union import pydantic -from pydantic.datetime_parse import parse_date, parse_datetime, parse_time +from pydantic_core import SchemaValidator, core_schema try: import orjson as json @@ -72,11 +72,12 @@ def re_dump_value(value: str) -> Union[str, bytes]: SQL_ENCODERS_MAP: Dict[type, Callable] = {bool: encode_bool, **ENCODERS_MAP} + DECODERS_MAP = { bool: parse_bool, - datetime.datetime: parse_datetime, - datetime.date: parse_date, - datetime.time: parse_time, + datetime.datetime: SchemaValidator(core_schema.datetime_schema()).validate_python, + datetime.date: SchemaValidator(core_schema.date_schema()).validate_python, + datetime.time: SchemaValidator(core_schema.time_schema()).validate_python, pydantic.Json: json.loads, decimal.Decimal: decimal.Decimal, } diff --git a/ormar/models/helpers/models.py b/ormar/models/helpers/models.py index 5bc0a0f3d..9a106346e 100644 --- a/ormar/models/helpers/models.py +++ b/ormar/models/helpers/models.py @@ -3,7 +3,7 @@ from typing import Any, Dict, List, TYPE_CHECKING, Tuple, Type import pydantic -from pydantic.typing import ForwardRef +from typing import ForwardRef import ormar # noqa: I100 from ormar.models.helpers.pydantic import populate_pydantic_default_values from ormar.models.utils import Extra diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index 7b5fb8244..8ab208d9d 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -3,7 +3,8 @@ from typing import Dict, Optional, TYPE_CHECKING, Tuple, Type, Union import pydantic -from pydantic.fields import ModelField +from pydantic import ConfigDict +from pydantic.fields import Field from pydantic.utils import lenient_issubclass from ormar.exceptions import ModelDefinitionError # noqa: I100, I202 @@ -30,7 +31,7 @@ def create_pydantic_field( :param model_field: relation field from which through model is extracted :type model_field: ManyToManyField class """ - model_field.through.__fields__[field_name] = ModelField( + model_field.through.__fields__[field_name] = Field( name=field_name, type_=model, model_config=model.__config__, @@ -39,7 +40,7 @@ def create_pydantic_field( ) -def get_pydantic_field(field_name: str, model: Type["Model"]) -> "ModelField": +def get_pydantic_field(field_name: str, model: Type["Model"]) -> "Field": """ Extracts field type and if it's required from Model model_fields by passed field_name. Returns a pydantic field with type of field_name field type. @@ -49,10 +50,10 @@ def get_pydantic_field(field_name: str, model: Type["Model"]) -> "ModelField": :param model: type of field to register :type model: Model class :return: newly created pydantic field - :rtype: pydantic.ModelField + :rtype: pydantic.Field """ type_ = model.Meta.model_fields[field_name].__type__ - return ModelField( + return Field( name=field_name, type_=type_, # type: ignore model_config=model.__config__, @@ -107,23 +108,21 @@ def merge_or_generate_pydantic_config(attrs: Dict, name: str) -> None: :rtype: None """ - DefaultConfig = get_pydantic_base_orm_config() - if "Config" in attrs: - ProvidedConfig = attrs["Config"] - if not inspect.isclass(ProvidedConfig): + default_config = get_pydantic_base_orm_config() + if "model_config" in attrs: + provided_config = attrs["model_config"] + if not isinstance(provided_config, dict): raise ModelDefinitionError( - f"Config provided for class {name} has to be a class." + f"Config provided for class {name} has to be a dictionary." ) - class Config(ProvidedConfig, DefaultConfig): # type: ignore - pass - - attrs["Config"] = Config + config = default_config.update(provided_config) + attrs["model_config"] = config else: - attrs["Config"] = DefaultConfig + attrs["model_config"] = default_config -def get_pydantic_base_orm_config() -> Type[pydantic.BaseConfig]: +def get_pydantic_base_orm_config() -> pydantic.ConfigDict: """ Returns empty pydantic Config with orm_mode set to True. @@ -131,11 +130,7 @@ def get_pydantic_base_orm_config() -> Type[pydantic.BaseConfig]: :rtype: pydantic Config """ - class Config(pydantic.BaseConfig): - orm_mode = True - validate_assignment = True - - return Config + return ConfigDict(validate_assignment=True) def get_potential_fields(attrs: Union[Dict, MappingProxyType]) -> Dict: diff --git a/ormar/models/helpers/related_names_validation.py b/ormar/models/helpers/related_names_validation.py index 56497b2b7..bd4df64c0 100644 --- a/ormar/models/helpers/related_names_validation.py +++ b/ormar/models/helpers/related_names_validation.py @@ -1,6 +1,6 @@ from typing import Dict, List, Optional, TYPE_CHECKING, Type -from pydantic.typing import ForwardRef +from typing import ForwardRef import ormar # noqa: I100 if TYPE_CHECKING: # pragma no cover diff --git a/ormar/models/helpers/sqlalchemy.py b/ormar/models/helpers/sqlalchemy.py index b0ade1d02..537f8be8d 100644 --- a/ormar/models/helpers/sqlalchemy.py +++ b/ormar/models/helpers/sqlalchemy.py @@ -2,7 +2,7 @@ from typing import Dict, List, Optional, TYPE_CHECKING, Tuple, Type, Union import sqlalchemy -from pydantic.typing import ForwardRef +from typing import ForwardRef import ormar # noqa: I100, I202 from ormar.models.descriptors import RelationDescriptor diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index d25837dc1..007d8373e 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -12,14 +12,15 @@ Union, ) +from pydantic import model_validator, typing + try: import orjson as json except ImportError: # pragma: no cover import json # type: ignore # noqa: F401 import pydantic -from pydantic.class_validators import make_generic_validator -from pydantic.fields import ModelField, SHAPE_LIST +from pydantic.fields import Field import ormar # noqa: I100, I202 from ormar.models.helpers.models import meta_field_not_set @@ -73,7 +74,7 @@ def convert_value_if_needed(field: "BaseField", value: Any) -> Any: def generate_validator(ormar_field: "BaseField") -> Callable: choices = ormar_field.choices - def validate_choices(cls: type, value: Any, field: "ModelField") -> None: + def validate_choices(cls: type, value: Any, field: "Field") -> None: """ Validates if given value is in provided choices. @@ -182,11 +183,13 @@ def generate_pydantic_example( """ example: Dict[str, Any] = dict() exclude = exclude or set() - name_to_check = [name for name in pydantic_model.__fields__ if name not in exclude] + name_to_check = [ + name for name in pydantic_model.model_fields if name not in exclude + ] for name in name_to_check: - field = pydantic_model.__fields__[name] - type_ = field.type_ - if field.shape == SHAPE_LIST: + field = pydantic_model.model_fields[name] + type_ = field.annotation + if typing.get_origin(type_) is list: example[name] = [get_pydantic_example_repr(type_)] else: example[name] = get_pydantic_example_repr(type_) @@ -307,7 +310,7 @@ def populate_choices_validators(model: Type["Model"]) -> None: # noqa CCR001 for name, field in model.Meta.model_fields.items(): if check_if_field_has_choices(field) and name not in model._choices_fields: fields_with_choices.append(name) - validator = make_generic_validator(generate_validator(field)) + validator = model_validator(mode="before")(generate_validator(field)) model.__fields__[name].validators.append(validator) model._choices_fields.add(name) @@ -316,4 +319,6 @@ def populate_choices_validators(model: Type["Model"]) -> None: # noqa CCR001 fields_with_choices=fields_with_choices ) else: - model.Config.schema_extra = construct_schema_function_without_choices() + model.model_config[ + "schema_extra" + ] = construct_schema_function_without_choices() diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 36a3e7488..06027788e 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -549,7 +549,7 @@ def add_field_descriptor( setattr(new_model, name, PydanticDescriptor(name=name)) -class ModelMetaclass(pydantic.main.ModelMetaclass): +class ModelMetaclass(pydantic._internal._model_construction.ModelMetaclass): def __new__( # type: ignore # noqa: CCR001 mcs: "ModelMetaclass", name: str, bases: Any, attrs: dict ) -> "ModelMetaclass": diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index 5d186bb09..c4ee21a04 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -15,7 +15,7 @@ ) import pydantic -from pydantic.fields import ModelField +from pydantic.fields import Field from ormar.models.mixins.relation_mixin import RelationMixin # noqa: I100, I202 from ormar.queryset.utils import translate_list_to_dict @@ -26,7 +26,7 @@ class PydanticMixin(RelationMixin): __cache__: Dict[str, Type[pydantic.BaseModel]] = {} if TYPE_CHECKING: # pragma: no cover - __fields__: Dict[str, ModelField] + __fields__: Dict[str, Field] _skip_ellipsis: Callable _get_not_excluded_fields: Callable diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index 46ef451d1..851e08551 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -35,7 +35,7 @@ class SavePrepareMixin(RelationMixin, AliasMixin): _skip_ellipsis: Callable _json_fields: Set[str] _bytes_fields: Set[str] - __fields__: Dict[str, pydantic.fields.ModelField] + __fields__: Dict[str, pydantic.fields.Field] @classmethod def prepare_model_to_save(cls, new_kwargs: dict) -> dict: diff --git a/poetry.lock b/poetry.lock index 689fa463c..b3bb1d8cc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,9 +1,10 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.1 and should not be changed by hand. [[package]] name = "aiomysql" version = "0.2.0" description = "MySQL driver for asyncio." +category = "main" optional = true python-versions = ">=3.7" files = [ @@ -22,6 +23,7 @@ sa = ["sqlalchemy (>=1.3,<1.4)"] name = "aiopg" version = "1.4.0" description = "Postgres integration with asyncio." +category = "main" optional = true python-versions = ">=3.7" files = [ @@ -40,6 +42,7 @@ sa = ["sqlalchemy[postgresql-psycopg2binary] (>=1.3,<1.5)"] name = "aiosqlite" version = "0.19.0" description = "asyncio bridge to the standard sqlite3 module" +category = "main" optional = true python-versions = ">=3.7" files = [ @@ -54,10 +57,26 @@ typing_extensions = {version = ">=4.0", markers = "python_version < \"3.8\""} dev = ["aiounittest (==1.4.1)", "attribution (==1.6.2)", "black (==23.3.0)", "coverage[toml] (==7.2.3)", "flake8 (==5.0.4)", "flake8-bugbear (==23.3.12)", "flit (==3.7.1)", "mypy (==1.2.0)", "ufmt (==2.1.0)", "usort (==1.0.6)"] docs = ["sphinx (==6.1.3)", "sphinx-mdinclude (==0.5.3)"] +[[package]] +name = "annotated-types" +version = "0.5.0" +description = "Reusable constraint types to use with typing.Annotated" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, + {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + [[package]] name = "anyio" version = "3.7.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -80,6 +99,7 @@ trio = ["trio (<0.22)"] name = "asgi-lifespan" version = "2.1.0" description = "Programmatic startup/shutdown of ASGI apps." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -94,6 +114,7 @@ sniffio = "*" name = "astpretty" version = "2.1.0" description = "Pretty print the output of python stdlib `ast.parse`." +category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -108,6 +129,7 @@ typed = ["typed-ast"] name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" +category = "main" optional = true python-versions = ">=3.6" files = [ @@ -122,6 +144,7 @@ typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} name = "asyncpg" version = "0.27.0" description = "An asyncio PostgreSQL driver" +category = "main" optional = true python-versions = ">=3.7.0" files = [ @@ -175,6 +198,7 @@ test = ["flake8 (>=5.0.4,<5.1.0)", "uvloop (>=0.15.3)"] name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -196,6 +220,7 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "bandit" version = "1.7.5" description = "Security oriented static analyser for python code." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -219,6 +244,7 @@ yaml = ["PyYAML"] name = "black" version = "23.3.0" description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -269,6 +295,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "cached-property" version = "1.5.2" description = "A decorator for caching properties in classes." +category = "dev" optional = false python-versions = "*" files = [ @@ -280,6 +307,7 @@ files = [ name = "certifi" version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -291,6 +319,7 @@ files = [ name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." +category = "main" optional = true python-versions = "*" files = [ @@ -367,6 +396,7 @@ pycparser = "*" name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." +category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -378,6 +408,7 @@ files = [ name = "charset-normalizer" version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -462,6 +493,7 @@ files = [ name = "click" version = "8.1.3" description = "Composable command line interface toolkit" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -477,6 +509,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "codecov" version = "2.1.13" description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -492,6 +525,7 @@ requests = ">=2.7.9" name = "cognitive-complexity" version = "1.3.0" description = "Library to calculate Python functions cognitive complexity via code" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -505,6 +539,7 @@ setuptools = "*" name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -516,6 +551,7 @@ files = [ name = "coverage" version = "7.2.7" description = "Code coverage measurement for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -591,6 +627,7 @@ toml = ["tomli"] name = "cryptography" version = "41.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" optional = true python-versions = ">=3.7" files = [ @@ -632,6 +669,7 @@ test-randomorder = ["pytest-randomly"] name = "databases" version = "0.6.2" description = "Async database support for Python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -656,6 +694,7 @@ sqlite = ["aiosqlite"] name = "dataclasses" version = "0.6" description = "A backport of the dataclasses module for Python 3.6" +category = "dev" optional = false python-versions = "*" files = [ @@ -667,6 +706,7 @@ files = [ name = "distlib" version = "0.3.6" description = "Distribution utilities" +category = "dev" optional = false python-versions = "*" files = [ @@ -678,6 +718,7 @@ files = [ name = "exceptiongroup" version = "1.1.1" description = "Backport of PEP 654 (exception groups)" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -690,26 +731,28 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.98.0" +version = "0.100.0b1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.98.0-py3-none-any.whl", hash = "sha256:f4165fb1fe3610c52cb1b8282c1480de9c34bc270f56a965aa93a884c350d605"}, - {file = "fastapi-0.98.0.tar.gz", hash = "sha256:0d3c18886f652038262b5898fec6b09f4ca92ee23e9d9b1d1d24e429f84bf27b"}, + {file = "fastapi-0.100.0b1-py3-none-any.whl", hash = "sha256:3e45c7209410503e4f372e38d9f47ec01cc1e23bbd4a796f6dfe23023584f622"}, + {file = "fastapi-0.100.0b1.tar.gz", hash = "sha256:2e699a1c924ecbda8b4e942ddd04899038d9bfb39077a1ef7a3164879609dc11"}, ] [package.dependencies] -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<3.0.0" starlette = ">=0.27.0,<0.28.0" [package.extras] -all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" version = "3.12.2" description = "A platform independent file lock." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -725,6 +768,7 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "p name = "flake8" version = "3.9.2" description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -742,6 +786,7 @@ pyflakes = ">=2.3.0,<2.4.0" name = "flake8-bandit" version = "3.0.0" description = "Automated security testing with bandit and flake8." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -759,6 +804,7 @@ pycodestyle = "*" name = "flake8-black" version = "0.3.6" description = "flake8 plugin to call black as a code style validator" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -778,6 +824,7 @@ develop = ["build", "twine"] name = "flake8-bugbear" version = "23.3.12" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -796,6 +843,7 @@ dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", name = "flake8-builtins" version = "2.1.0" description = "Check for python builtins being used as variables or parameters." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -813,6 +861,7 @@ test = ["pytest"] name = "flake8-cognitive-complexity" version = "0.1.0" description = "An extension for flake8 that validates cognitive functions complexity" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -827,6 +876,7 @@ setuptools = "*" name = "flake8-expression-complexity" version = "0.0.11" description = "A flake8 extension that checks expressions complexity" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -842,6 +892,7 @@ flake8 = "*" name = "flake8-functions" version = "0.0.8" description = "A flake8 extension that checks functions" +category = "dev" optional = false python-versions = "*" files = [ @@ -857,6 +908,7 @@ setuptools = "*" name = "flake8-import-order" version = "0.18.2" description = "Flake8 and pylama plugin that checks the ordering of import statements." +category = "dev" optional = false python-versions = "*" files = [ @@ -872,6 +924,7 @@ setuptools = "*" name = "flake8-polyfill" version = "1.0.2" description = "Polyfill package for Flake8 plugins" +category = "dev" optional = false python-versions = "*" files = [ @@ -886,6 +939,7 @@ flake8 = "*" name = "flake8-variables-names" version = "0.0.6" description = "A flake8 extension that helps to make more readable variables names" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -897,6 +951,7 @@ files = [ name = "ghp-import" version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." +category = "dev" optional = false python-versions = "*" files = [ @@ -914,6 +969,7 @@ dev = ["flake8", "markdown", "twine", "wheel"] name = "gitdb" version = "4.0.10" description = "Git Object Database" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -928,6 +984,7 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.31" description = "GitPython is a Python library used to interact with Git repositories" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -943,6 +1000,7 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\"" name = "greenlet" version = "2.0.2" description = "Lightweight in-process concurrent programming" +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" files = [ @@ -1014,13 +1072,14 @@ test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.29.0" +version = "0.29.1" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "griffe-0.29.0-py3-none-any.whl", hash = "sha256:e62ff34b04630c2382e2e277301cb2c29221fb09c04028e62ef35afccc64344b"}, - {file = "griffe-0.29.0.tar.gz", hash = "sha256:6fc892aaa251b3761e3a8d2f5893758e1850ec5d81d4605c4557be0666202a0b"}, + {file = "griffe-0.29.1-py3-none-any.whl", hash = "sha256:f9edae6b9bb2eb205bebbdd0512a162713b9342ff6e32dc596d95ff64aa71c1f"}, + {file = "griffe-0.29.1.tar.gz", hash = "sha256:460188b719e363019d0d0f4bf2d9f05cf2df24960b42a4138a1524a17b100d9b"}, ] [package.dependencies] @@ -1031,6 +1090,7 @@ colorama = ">=0.4" name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1045,6 +1105,7 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} name = "httpcore" version = "0.17.2" description = "A minimal low-level HTTP client." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1056,16 +1117,17 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = "==1.*" +sniffio = ">=1.0.0,<2.0.0" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" version = "0.24.1" description = "The next generation HTTP client." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1081,14 +1143,15 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "identify" version = "2.5.24" description = "File identification library for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1103,6 +1166,7 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1114,6 +1178,7 @@ files = [ name = "importlib-metadata" version = "6.7.0" description = "Read metadata from Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1134,6 +1199,7 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1145,6 +1211,7 @@ files = [ name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1162,6 +1229,7 @@ i18n = ["Babel (>=2.7)"] name = "markdown" version = "3.3.7" description = "Python implementation of Markdown." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1179,6 +1247,7 @@ testing = ["coverage", "pyyaml"] name = "markdown-it-py" version = "2.2.0" description = "Python port of markdown-it. Markdown parsing, done right!" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1204,6 +1273,7 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1263,6 +1333,7 @@ files = [ name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = "*" files = [ @@ -1274,6 +1345,7 @@ files = [ name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1285,6 +1357,7 @@ files = [ name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1296,6 +1369,7 @@ files = [ name = "mkdocs" version = "1.4.3" description = "Project documentation with Markdown." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1325,6 +1399,7 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp name = "mkdocs-autorefs" version = "0.4.1" description = "Automatically link across pages in MkDocs." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1340,6 +1415,7 @@ mkdocs = ">=1.1" name = "mkdocs-gen-files" version = "0.5.0" description = "MkDocs plugin to programmatically generate documentation pages during the build" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1354,6 +1430,7 @@ mkdocs = ">=1.0.3" name = "mkdocs-literate-nav" version = "0.6.0" description = "MkDocs plugin to specify the navigation in Markdown instead of YAML" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1368,6 +1445,7 @@ mkdocs = ">=1.0.3" name = "mkdocs-material" version = "9.1.17" description = "Documentation that simply works" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1390,6 +1468,7 @@ requests = ">=2.26" name = "mkdocs-material-extensions" version = "1.1.1" description = "Extension pack for Python Markdown and MkDocs Material." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1401,6 +1480,7 @@ files = [ name = "mkdocs-section-index" version = "0.3.5" description = "MkDocs plugin to allow clickable sections that lead to an index page" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1415,6 +1495,7 @@ mkdocs = ">=1.0.3" name = "mkdocstrings" version = "0.22.0" description = "Automatic documentation from sources, for MkDocs." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1442,6 +1523,7 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] name = "mkdocstrings-python" version = "1.1.2" description = "A Python handler for mkdocstrings." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1457,6 +1539,7 @@ mkdocstrings = ">=0.20" name = "mr-proper" version = "0.0.7" description = "Static Python code analyzer, that tries to check if functions in code are pure or not and why." +category = "dev" optional = false python-versions = "*" files = [ @@ -1474,6 +1557,7 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\"" name = "mypy" version = "0.982" description = "Optional static typing for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1518,6 +1602,7 @@ reports = ["lxml"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1529,6 +1614,7 @@ files = [ name = "mysqlclient" version = "2.1.1" description = "Python interface to MySQL" +category = "main" optional = true python-versions = ">=3.5" files = [ @@ -1545,6 +1631,7 @@ files = [ name = "nest-asyncio" version = "1.5.6" description = "Patch asyncio to allow nested event loops" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1556,6 +1643,7 @@ files = [ name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" +category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -1570,6 +1658,7 @@ setuptools = "*" name = "orjson" version = "3.9.1" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1625,6 +1714,7 @@ files = [ name = "packaging" version = "23.1" description = "Core utilities for Python packages" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1636,6 +1726,7 @@ files = [ name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1647,6 +1738,7 @@ files = [ name = "pbr" version = "5.11.1" description = "Python Build Reasonableness" +category = "dev" optional = false python-versions = ">=2.6" files = [ @@ -1656,13 +1748,14 @@ files = [ [[package]] name = "platformdirs" -version = "3.6.0" +version = "3.8.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.6.0-py3-none-any.whl", hash = "sha256:ffa199e3fbab8365778c4a10e1fbf1b9cd50707de826eb304b50e57ec0cc8d38"}, - {file = "platformdirs-3.6.0.tar.gz", hash = "sha256:57e28820ca8094678b807ff529196506d7a21e17156cb1cddb3e74cebce54640"}, + {file = "platformdirs-3.8.0-py3-none-any.whl", hash = "sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"}, + {file = "platformdirs-3.8.0.tar.gz", hash = "sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc"}, ] [package.dependencies] @@ -1674,13 +1767,14 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest- [[package]] name = "pluggy" -version = "1.0.0" +version = "1.2.0" description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, ] [package.dependencies] @@ -1694,6 +1788,7 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1713,6 +1808,7 @@ virtualenv = ">=20.10.0" name = "psycopg2-binary" version = "2.9.6" description = "psycopg2 - Python-PostgreSQL Database Adapter" +category = "main" optional = true python-versions = ">=3.6" files = [ @@ -1784,6 +1880,7 @@ files = [ name = "py-cpuinfo" version = "9.0.0" description = "Get CPU info with pure Python" +category = "dev" optional = false python-versions = "*" files = [ @@ -1795,6 +1892,7 @@ files = [ name = "pycodestyle" version = "2.7.0" description = "Python style guide checker" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1806,6 +1904,7 @@ files = [ name = "pycparser" version = "2.21" description = "C parser in Python" +category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1815,60 +1914,123 @@ files = [ [[package]] name = "pydantic" -version = "1.10.9" -description = "Data validation and settings management using python type hints" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pydantic-1.10.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e692dec4a40bfb40ca530e07805b1208c1de071a18d26af4a2a0d79015b352ca"}, - {file = "pydantic-1.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c52eb595db83e189419bf337b59154bdcca642ee4b2a09e5d7797e41ace783f"}, - {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939328fd539b8d0edf244327398a667b6b140afd3bf7e347cf9813c736211896"}, - {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b48d3d634bca23b172f47f2335c617d3fcb4b3ba18481c96b7943a4c634f5c8d"}, - {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f0b7628fb8efe60fe66fd4adadd7ad2304014770cdc1f4934db41fe46cc8825f"}, - {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e1aa5c2410769ca28aa9a7841b80d9d9a1c5f223928ca8bec7e7c9a34d26b1d4"}, - {file = "pydantic-1.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:eec39224b2b2e861259d6f3c8b6290d4e0fbdce147adb797484a42278a1a486f"}, - {file = "pydantic-1.10.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d111a21bbbfd85c17248130deac02bbd9b5e20b303338e0dbe0faa78330e37e0"}, - {file = "pydantic-1.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e9aec8627a1a6823fc62fb96480abe3eb10168fd0d859ee3d3b395105ae19a7"}, - {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07293ab08e7b4d3c9d7de4949a0ea571f11e4557d19ea24dd3ae0c524c0c334d"}, - {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee829b86ce984261d99ff2fd6e88f2230068d96c2a582f29583ed602ef3fc2c"}, - {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b466a23009ff5cdd7076eb56aca537c745ca491293cc38e72bf1e0e00de5b91"}, - {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7847ca62e581e6088d9000f3c497267868ca2fa89432714e21a4fb33a04d52e8"}, - {file = "pydantic-1.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:7845b31959468bc5b78d7b95ec52fe5be32b55d0d09983a877cca6aedc51068f"}, - {file = "pydantic-1.10.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:517a681919bf880ce1dac7e5bc0c3af1e58ba118fd774da2ffcd93c5f96eaece"}, - {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67195274fd27780f15c4c372f4ba9a5c02dad6d50647b917b6a92bf00b3d301a"}, - {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2196c06484da2b3fded1ab6dbe182bdabeb09f6318b7fdc412609ee2b564c49a"}, - {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6257bb45ad78abacda13f15bde5886efd6bf549dd71085e64b8dcf9919c38b60"}, - {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3283b574b01e8dbc982080d8287c968489d25329a463b29a90d4157de4f2baaf"}, - {file = "pydantic-1.10.9-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8bbaf4013b9a50e8100333cc4e3fa2f81214033e05ac5aa44fa24a98670a29"}, - {file = "pydantic-1.10.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9cd67fb763248cbe38f0593cd8611bfe4b8ad82acb3bdf2b0898c23415a1f82"}, - {file = "pydantic-1.10.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f50e1764ce9353be67267e7fd0da08349397c7db17a562ad036aa7c8f4adfdb6"}, - {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73ef93e5e1d3c8e83f1ff2e7fdd026d9e063c7e089394869a6e2985696693766"}, - {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128d9453d92e6e81e881dd7e2484e08d8b164da5507f62d06ceecf84bf2e21d3"}, - {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ad428e92ab68798d9326bb3e5515bc927444a3d71a93b4a2ca02a8a5d795c572"}, - {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fab81a92f42d6d525dd47ced310b0c3e10c416bbfae5d59523e63ea22f82b31e"}, - {file = "pydantic-1.10.9-cp38-cp38-win_amd64.whl", hash = "sha256:963671eda0b6ba6926d8fc759e3e10335e1dc1b71ff2a43ed2efd6996634dafb"}, - {file = "pydantic-1.10.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:970b1bdc6243ef663ba5c7e36ac9ab1f2bfecb8ad297c9824b542d41a750b298"}, - {file = "pydantic-1.10.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7e1d5290044f620f80cf1c969c542a5468f3656de47b41aa78100c5baa2b8276"}, - {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83fcff3c7df7adff880622a98022626f4f6dbce6639a88a15a3ce0f96466cb60"}, - {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0da48717dc9495d3a8f215e0d012599db6b8092db02acac5e0d58a65248ec5bc"}, - {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0a2aabdc73c2a5960e87c3ffebca6ccde88665616d1fd6d3db3178ef427b267a"}, - {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9863b9420d99dfa9c064042304868e8ba08e89081428a1c471858aa2af6f57c4"}, - {file = "pydantic-1.10.9-cp39-cp39-win_amd64.whl", hash = "sha256:e7c9900b43ac14110efa977be3da28931ffc74c27e96ee89fbcaaf0b0fe338e1"}, - {file = "pydantic-1.10.9-py3-none-any.whl", hash = "sha256:6cafde02f6699ce4ff643417d1a9223716ec25e228ddc3b436fe7e2d25a1f305"}, - {file = "pydantic-1.10.9.tar.gz", hash = "sha256:95c70da2cd3b6ddf3b9645ecaa8d98f3d80c606624b6d245558d202cd23ea3be"}, -] - -[package.dependencies] -typing-extensions = ">=4.2.0" +version = "2.0b3" +description = "Data validation using Python type hints" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic-2.0b3-py3-none-any.whl", hash = "sha256:dd6a8f835aceef1a399329478c355c91985f582afda7027055834d6822aa0ce2"}, + {file = "pydantic-2.0b3.tar.gz", hash = "sha256:057fb3050b8d3952153a0df45188882096ac53fe087b196fd0d877442b0c029b"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "0.39.0" +typing-extensions = ">=4.6.1" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "0.39.0" +description = "" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-0.39.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:361135e456636aecad3c15ceabc206fe93b4f86778ca24eefd707952954b7e70"}, + {file = "pydantic_core-0.39.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c9c16fc80e2612b0121eb425890e2e29f03e3038bbd53e5b637cd72aad2c5339"}, + {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73f785920e974f86d2e37a7fc44a5fdd3e9b6d40fba94137da7a1e02c4dd7c11"}, + {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9e18e91b5f4172ea5ebc8fe0461acf6f2de73d4b85b47aee26924dcd304141a"}, + {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_24_armv7l.whl", hash = "sha256:ac8756c26cbfc57e89ff52817a2802e97376948de002ffe39adb238fbb12c8db"}, + {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:8ac4ba34ac3977fa5c6cef5921564133e1295b9d202fed2d6e62187f61651f3c"}, + {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_24_s390x.whl", hash = "sha256:f8992a135442959269d2c013bd9913c837d5ea215b0e480cda1820c7310df55b"}, + {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3cb0cdc1c5c036aa7caccf6a28e9a2ce3058ae18aceb143870a6a379235b075d"}, + {file = "pydantic_core-0.39.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:30ad66243a64818e8afb584596cc9f7f8738406ffe1b4ab0be00e23375753b7c"}, + {file = "pydantic_core-0.39.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e86833a13a4f00f264d04f3f36048ce3fea0a92a730db6c9c9c0bf33e277bc2"}, + {file = "pydantic_core-0.39.0-cp310-none-win32.whl", hash = "sha256:dc12b16753591143bdd0c117d74fbe46fda84b4a8eb0383931811819d8679c89"}, + {file = "pydantic_core-0.39.0-cp310-none-win_amd64.whl", hash = "sha256:ddf0177f2324200cf9ea3100d4232be275c8986a4cb9b1892e1f53d2584f6b17"}, + {file = "pydantic_core-0.39.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:9f1ddc997865f29eee3fea397885595d361a76df80356fec8c47f45b987b7490"}, + {file = "pydantic_core-0.39.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7ad056aeb02a474957fa950ff169549e214cec5f0b5c18dae683b0d21227def"}, + {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8178dc88a246c60fb8264a8422587abc209cac1d9160329af8a6f5f89797cb3"}, + {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:126db921ac7c72cb5d8d1b46540d594d559c25e243b3515aed040a0cd0eafac8"}, + {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:d3a8d0734b1e82df4a725fa39a1b78625c407b8cf31ae1652382a2f4c8c757b4"}, + {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:87e4d828c0cc28e8ec1abad2e83110e0cca175b3799fc3eeab22e615cefc551f"}, + {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:472049006abb4070750d530c96d76122497aec86b99c618d583e596fe986ad0a"}, + {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9595444868ece2e67b5e64a583eab10756491d9bf4e6d3876410299297d4adb3"}, + {file = "pydantic_core-0.39.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:00c3a5ab18f355a0b082019fdc4af41b61c4a2e33d97af44c69b611d818bdfe2"}, + {file = "pydantic_core-0.39.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7bf7470f621285303a5aa6b3e4fb148c5b69f8ee485a920ee9cc1472fd282d2e"}, + {file = "pydantic_core-0.39.0-cp311-none-win32.whl", hash = "sha256:3696a567b7517c09ed7dae942fa5b38cd552af5160d0905b76e9607b87e31d01"}, + {file = "pydantic_core-0.39.0-cp311-none-win_amd64.whl", hash = "sha256:c9b4909e971e8745af251cecd92aa55f9239bbc9a9630811dd53a00a2b5285f8"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9aba06c25f356c0fb11f1dd2d0317a5599f223a3b283ebbc1aa3a1100a6920f7"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:bd5f3e98d112c6eab8c41cf2baf3dab8006c3223d5f2c9695b1cba7ab87bbfb5"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351a34da43f44a52bbd52380322bfb364f2efe423275c4917c8c26100c1b8ced"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ac25daeb3ea45ecd4e8580f7375e6434daf02c6ca185f246f2e682de554ab5"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_24_armv7l.whl", hash = "sha256:45926ab2adef2deff4fc89e12bf5ba015ad297efefcd0f84b8689123a6c3b126"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:549a0940b7164b23d52df4d6bd73637e989688d28dbeb9e24d87a27da48f23bc"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_24_s390x.whl", hash = "sha256:a0f7d1454f86865cd2ec47e36ebe2e20cca5be71eaa5c2e422adf1e0355ae705"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8849794ae4da5d244d215ee582e83e169120c475a7e05f1adf227035b9edbde3"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e9f98a9df2cea76b1a8bd70d00b4ee3b7597887281c2e85c8ad690ed881ef34"}, + {file = "pydantic_core-0.39.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1f89064cf78b57bf2930a14b41aa4b4240bd2993a57efb56b5ad8be02f4048b3"}, + {file = "pydantic_core-0.39.0-cp37-none-win32.whl", hash = "sha256:2bfe35d886d93c7911b4d56ab3a6725a7866b35f09aceaf3d0d64babed701b73"}, + {file = "pydantic_core-0.39.0-cp37-none-win_amd64.whl", hash = "sha256:84675545b74ce4ea53f0e2413f182db1501b1684d6359f7c2cb4d37d24a9afec"}, + {file = "pydantic_core-0.39.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:abbcbc69868ad7f642caa319a7b5f829e6f9b6db5194b6b82b7a9561ac992663"}, + {file = "pydantic_core-0.39.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a5ca573f261ea525c5bb10e03d41dd9ce76aea93b75f9ca2dc5dc4ef147ea2a3"}, + {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1f187d852ca78b9e23a0155be5f759f65f5e5c7dc4b29b7ea7aa5df48537ba1"}, + {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4060e765690727095969f7038e8e1c7251d4bd518e151174b5cb54dae0163c68"}, + {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_24_armv7l.whl", hash = "sha256:b749a22e311e235974516a4bca00afdf4f2e67dd7773d3850c1b17f1da1131b1"}, + {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:749c0a2038ca7fb3a29ff7f9ce7d3248d8bb9f42d2ef609b4e4c158e74368145"}, + {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_24_s390x.whl", hash = "sha256:e77a053384a29c4ffdad2a717809e347b864c582c407ab88eb9ff3fa3bce22a7"}, + {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef212fafe222ae7fdf38ba16b5c7bb7eddf1b44cc901bc3056569eefcf54da94"}, + {file = "pydantic_core-0.39.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9602b61c85d9c12b0e66792eebc85152b565c24431a69c47f3cba811b1507389"}, + {file = "pydantic_core-0.39.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5ccb4a21713a831f888c0bf22be4888df475650f699cc35a675cb91cc55e780b"}, + {file = "pydantic_core-0.39.0-cp38-none-win32.whl", hash = "sha256:3a5795a0521ce88adbffd16796e85cdd06546805ff869fed0cac1a9c297d9445"}, + {file = "pydantic_core-0.39.0-cp38-none-win_amd64.whl", hash = "sha256:dc8234bd4325341eb660a86dba3688a5287789309a84261b3dbe76d4dd0472e8"}, + {file = "pydantic_core-0.39.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:c2fb59f98fd0f9f3ee1b77b2c44f282ed8b1cc52d332c2d2a34b6364f63dbfa1"}, + {file = "pydantic_core-0.39.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:103179d734dafb5da5f74065d1a18274709684a9dc01c61f119c5e39dea4d2df"}, + {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3b42892739cd3e27c2efbab6682fa91ec07c76381db1ca66da2d889c21e1c8a"}, + {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0203bc58c551d018bff3ce3bc863cd2c88504dbb96f79357fdaa22955db64ffe"}, + {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_24_armv7l.whl", hash = "sha256:bb4cea3c63defa0fe891af206ad04c8b167852feb6bfba7c1cc4f26a4a2eb39e"}, + {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:17a08e9af181097759362182bffa5614cd8c1278f12bab529e6e3bdc4b2d3860"}, + {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_24_s390x.whl", hash = "sha256:5438ffb320ad430de40de405078b0770beb1eec00e54de18a63c842d114d86b9"}, + {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf55dc04bb037c06d256e22254401b10fbc3a478835837987435e3c77ec929f9"}, + {file = "pydantic_core-0.39.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c7b5e09e5e6c7cf2ed0ccb5a1ddf1f6d12131315ff70d100fc197711df4a37e"}, + {file = "pydantic_core-0.39.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0ef384f3b4aa5ef4c66d47f4446ca9dc8adbfbc7bf74d1b31b19cc2e2bdf9e8"}, + {file = "pydantic_core-0.39.0-cp39-none-win32.whl", hash = "sha256:579c69e5a7bf2fd3dedd3c51e91b1beb0c89782ea6c0d1ffd8e48259b70f9d61"}, + {file = "pydantic_core-0.39.0-cp39-none-win_amd64.whl", hash = "sha256:3a4d4d87dc988d9c52d4e7e31b77d6036b4cab36109826b57cd293ae3179440d"}, + {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d3240340147504a1d6a3c86f43b644469f8c61992e0d88287701ee8f6b1b0b2d"}, + {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d32b45650e5bb8670b73d0f9acdae184197308f5a5ecf8e714849c76fd0a6ed"}, + {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ee34d942a3ab3d55db4945b42ce000c5ca2fd749ab9bbc3fb4ddab41742cbbd"}, + {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5570c884284a5e69278c4bb259c1694d64a5d9bc9a28674d088134246ad73358"}, + {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a5a377d9bf58a99e55d74167c658cb1f170cc1c008b849f5a8ec31b7b0eb65e7"}, + {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:45f55076c3844ccf1a9f912d5bef61282baae203b30a7b0158add0b4a2141036"}, + {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:e7d2a139d384911ee97ad2e9472ae4e79e9fedf278fa8c31b3e391c0279c0207"}, + {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f29f3197b1b50550c299ad8700918fbe383412df6f864fe02190a958b60a3c29"}, + {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71e12169625eb4b6939617333dd1aa671c156a44c44880db207c47a2e4c9fe81"}, + {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:058ea15957753eeb0547bbcb9aca1dca1f11969f0517a6f988d708110c4717e4"}, + {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:711d3a4c9ed8cce84dd55284ff9f4494b825930154a52a37cd02ac4e3a5fd62d"}, + {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5cf2849e22925411a15d955c03197f71c6507fcdfcaeee110a7202f6e436b5fa"}, + {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cf6cff67dcf885f36e9f8a8771225df6b9cd76f308d0c7af66bfd2776f471c7c"}, + {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:96100fb53a7384a99c6121ea90f01aa1cb6100af8dd25f227a5132f38b9199df"}, + {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bed383476707e6aeb8d9d6fc83a9b9a6b4f0a00ae440ca3f1cc17686ae3e45ab"}, + {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4908e1bbafa91dcbcc8778bfe11ede713ef18dafac4a7f66b7108d348d46e5ea"}, + {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2c52a9269c302b75265e45f72e1c3a3d4e473c90f11d3c5671ddfa7ba891eae"}, + {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:99de1fe8dcb3dc6e853ff6b96da4faa54384bbc4e73dbeb7dc8473f7e9d84243"}, + {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b2352ef56d0a5157dea6d39f3342980523673ac7f08967e39a68e06c168b94a4"}, + {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7cdcd13b84411d6194de988044b21c2859fcc7c673e0f6dd92e854489c21ae2f"}, + {file = "pydantic_core-0.39.0.tar.gz", hash = "sha256:8368d0510d0020d1bbb4124b31fb663e17e5661b5cc85c48e2b9d9bb0a378d9f"}, +] + +[package.dependencies] +typing_extensions = {version = "*", markers = "python_version < \"3.11.0\""} [[package]] name = "pyflakes" version = "2.3.1" description = "passive checker of Python programs" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1880,6 +2042,7 @@ files = [ name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1894,6 +2057,7 @@ plugins = ["importlib-metadata"] name = "pymdown-extensions" version = "10.0.1" description = "Extension pack for Python Markdown." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1907,13 +2071,14 @@ pyyaml = "*" [[package]] name = "pymysql" -version = "1.0.3" +version = "1.1.0" description = "Pure Python MySQL Driver" +category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "PyMySQL-1.0.3-py3-none-any.whl", hash = "sha256:89fc6ae41c0aeb6e1f7710cdd623702ea2c54d040565767a78b00a5ebb12f4e5"}, - {file = "PyMySQL-1.0.3.tar.gz", hash = "sha256:3dda943ef3694068a75d69d071755dbecacee1adf9a1fc5b206830d2b67d25e8"}, + {file = "PyMySQL-1.1.0-py3-none-any.whl", hash = "sha256:8969ec6d763c856f7073c4c64662882675702efcb114b4bcbb955aea3a069fa7"}, + {file = "PyMySQL-1.1.0.tar.gz", hash = "sha256:4f13a7df8bf36a51e81dd9f3605fede45a4878fe02f9236349fd82a3f0612f96"}, ] [package.extras] @@ -1924,6 +2089,7 @@ rsa = ["cryptography"] name = "pytest" version = "7.4.0" description = "pytest: simple powerful testing with Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1947,6 +2113,7 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-asyncio" version = "0.21.0" description = "Pytest support for asyncio" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1966,6 +2133,7 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy name = "pytest-benchmark" version = "4.0.0" description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1986,6 +2154,7 @@ histogram = ["pygal", "pygaljs"] name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2004,6 +2173,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2018,6 +2188,7 @@ six = ">=1.5" name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2067,6 +2238,7 @@ files = [ name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2081,6 +2253,7 @@ pyyaml = "*" name = "regex" version = "2023.6.3" description = "Alternative regular expression module, to replace re." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2178,6 +2351,7 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2199,6 +2373,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "rich" version = "13.4.2" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -2216,13 +2391,14 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "67.8.0" +version = "68.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, - {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, ] [package.extras] @@ -2234,6 +2410,7 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2245,6 +2422,7 @@ files = [ name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2256,6 +2434,7 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2267,6 +2446,7 @@ files = [ name = "sqlalchemy" version = "1.4.41" description = "Database Abstraction Library" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -2314,7 +2494,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""} importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [package.extras] @@ -2342,6 +2522,7 @@ sqlcipher = ["sqlcipher3-binary"] name = "starlette" version = "0.27.0" description = "The little ASGI library that shines." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2358,22 +2539,28 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam [[package]] name = "stdlib-list" -version = "0.8.0" -description = "A list of Python Standard Libraries (2.6-7, 3.2-9)." +version = "0.9.0" +description = "A list of Python Standard Libraries (2.7 through 3.9)." +category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "stdlib-list-0.8.0.tar.gz", hash = "sha256:a1e503719720d71e2ed70ed809b385c60cd3fb555ba7ec046b96360d30b16d9f"}, - {file = "stdlib_list-0.8.0-py3-none-any.whl", hash = "sha256:2ae0712a55b68f3fbbc9e58d6fa1b646a062188f49745b495f94d3310a9fdd3e"}, + {file = "stdlib_list-0.9.0-py3-none-any.whl", hash = "sha256:f79957d59e41930d44afcd81e465f740b9a7a9828707a40e24ab1092b12bd423"}, + {file = "stdlib_list-0.9.0.tar.gz", hash = "sha256:98eb66135976c96b4ee3f4c0ef0552ebb5a9977ce3028433db79f4738b02af26"}, ] [package.extras] -develop = ["sphinx"] +dev = ["build", "stdlib-list[doc,lint,test]"] +doc = ["furo", "sphinx"] +lint = ["black", "mypy", "ruff"] +support = ["sphobjinv"] +test = ["coverage[toml]", "pytest", "pytest-cov"] [[package]] name = "stevedore" version = "3.5.2" description = "Manage dynamic plugins for Python applications" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2389,6 +2576,7 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" name = "tomli" version = "2.0.1" description = "A lil' TOML parser" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2400,6 +2588,7 @@ files = [ name = "typed-ast" version = "1.5.4" description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2433,6 +2622,7 @@ files = [ name = "types-aiofiles" version = "23.1.0.4" description = "Typing stubs for aiofiles" +category = "dev" optional = false python-versions = "*" files = [ @@ -2444,6 +2634,7 @@ files = [ name = "types-cryptography" version = "3.3.23.2" description = "Typing stubs for cryptography" +category = "dev" optional = false python-versions = "*" files = [ @@ -2455,6 +2646,7 @@ files = [ name = "types-enum34" version = "1.1.8" description = "Typing stubs for enum34" +category = "dev" optional = false python-versions = "*" files = [ @@ -2466,6 +2658,7 @@ files = [ name = "types-ipaddress" version = "1.0.8" description = "Typing stubs for ipaddress" +category = "dev" optional = false python-versions = "*" files = [ @@ -2477,6 +2670,7 @@ files = [ name = "types-orjson" version = "3.6.2" description = "Typing stubs for orjson" +category = "dev" optional = false python-versions = "*" files = [ @@ -2488,6 +2682,7 @@ files = [ name = "types-pkg-resources" version = "0.1.3" description = "Typing stubs for pkg_resources" +category = "dev" optional = false python-versions = "*" files = [ @@ -2499,6 +2694,7 @@ files = [ name = "types-pymysql" version = "1.0.19.7" description = "Typing stubs for PyMySQL" +category = "dev" optional = false python-versions = "*" files = [ @@ -2510,6 +2706,7 @@ files = [ name = "types-requests" version = "2.31.0.1" description = "Typing stubs for requests" +category = "dev" optional = false python-versions = "*" files = [ @@ -2524,6 +2721,7 @@ types-urllib3 = "*" name = "types-toml" version = "0.10.8.6" description = "Typing stubs for toml" +category = "dev" optional = false python-versions = "*" files = [ @@ -2535,6 +2733,7 @@ files = [ name = "types-ujson" version = "5.8.0.0" description = "Typing stubs for ujson" +category = "dev" optional = false python-versions = "*" files = [ @@ -2546,6 +2745,7 @@ files = [ name = "types-urllib3" version = "1.26.25.13" description = "Typing stubs for urllib3" +category = "dev" optional = false python-versions = "*" files = [ @@ -2557,6 +2757,7 @@ files = [ name = "typing-extensions" version = "4.6.3" description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2568,6 +2769,7 @@ files = [ name = "urllib3" version = "2.0.3" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2585,6 +2787,7 @@ zstd = ["zstandard (>=0.18.0)"] name = "virtualenv" version = "20.23.1" description = "Virtual Python Environment builder" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2606,6 +2809,7 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess name = "watchdog" version = "3.0.0" description = "Filesystem events monitoring" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2645,6 +2849,7 @@ watchmedo = ["PyYAML (>=3.10)"] name = "yappi" version = "1.4.0" description = "Yet Another Python Profiler" +category = "dev" optional = false python-versions = "*" files = [ @@ -2700,6 +2905,7 @@ test = ["gevent (>=20.6.2)"] name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2724,4 +2930,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.7.0" -content-hash = "2c519f2e430d9063d0045fcf3e2ae3c5f1f2b24195509a5e9068274a57f66d96" +content-hash = "95546ecc08755aca3157a1fb072c0e7623c2b6af8acc8d4e38fe7672239dca81" diff --git a/pyproject.toml b/pyproject.toml index f49ac49b8..7200ce9c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.7.0" databases = ">=0.3.2,!=0.5.0,!=0.5.1,!=0.5.2,!=0.5.3,<0.6.3" -pydantic = ">=1.6.1,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<1.10.10" +pydantic = ">=v2.0b3" SQLAlchemy = ">=1.3.18,<1.4.42" cryptography = { version = ">=35,<42", optional = true } # Async database drivers @@ -76,7 +76,7 @@ pytest = "^7.4.0" pytest-cov = "^4.0.0" codecov = "^2.1.13" pytest-asyncio = "^0.21.0" -fastapi = ">=0.70.1,<=0.98.0" +fastapi = ">=0.100.0-beta1" flake8 = "^3.9.2" flake8-black = "^0.3.6" flake8-bugbear = "^23.3.12" diff --git a/tests/test_types.py b/tests/test_types.py index b5122a8ee..b55a8f330 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -12,23 +12,23 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - - class Publisher(ormar.Model): - class Meta(BaseMeta): - tablename = "publishers" + + model_config = dict( + metadata=metadata, + database=database, + table_name="publishers", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" - order_by = ["-name"] + + model_config = dict( + metadata=metadata, database=database, table_name="authors", order_by=["-name"] + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -36,9 +36,13 @@ class Meta(BaseMeta): class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" - order_by = ["year", "-ranking"] + + model_config = dict( + metadata=metadata, + database=database, + table_name="books", + order_by=["year", "-ranking"], + ) id: int = ormar.Integer(primary_key=True) author = ormar.ForeignKey(Author) From c95aafc8358c1eb7c7c878d57555df3c233e325c Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 13 Dec 2023 16:56:48 +0100 Subject: [PATCH 02/95] WIP - make test_model_definition tests pass --- ormar/__init__.py | 1 + ormar/fields/base.py | 10 +- ormar/fields/foreign_key.py | 20 +- ormar/fields/many_to_many.py | 31 +- ormar/fields/model_fields.py | 53 - ormar/models/__init__.py | 11 +- ormar/models/descriptors/descriptors.py | 6 +- ormar/models/helpers/__init__.py | 8 +- ormar/models/helpers/models.py | 56 +- ormar/models/helpers/pydantic.py | 15 +- ormar/models/helpers/relations.py | 23 +- ormar/models/helpers/sqlalchemy.py | 53 +- ormar/models/helpers/validation.py | 65 +- ormar/models/metaclass.py | 70 +- ormar/models/mixins/alias_mixin.py | 12 +- ormar/models/mixins/excludable_mixin.py | 12 +- ormar/models/mixins/relation_mixin.py | 20 +- ormar/models/mixins/save_mixin.py | 34 +- ormar/models/model.py | 43 +- ormar/models/model_row.py | 16 +- ormar/models/newbasemodel.py | 94 +- ormar/models/ormar_config.py | 67 + ormar/models/quick_access_views.py | 2 +- ormar/models/traversible.py | 2 +- ormar/queryset/actions/filter_action.py | 6 +- ormar/queryset/actions/order_action.py | 8 +- ormar/queryset/actions/query_action.py | 4 +- ormar/queryset/clause.py | 10 +- ormar/queryset/field_accessor.py | 5 +- ormar/queryset/join.py | 28 +- ormar/queryset/queries/query.py | 8 +- ormar/queryset/queryset.py | 14 +- ormar/queryset/utils.py | 8 +- ormar/relations/alias_manager.py | 2 +- ormar/relations/querysetproxy.py | 4 +- ormar/relations/relation_proxy.py | 4 +- poetry.lock | 1515 +++++++++-------- pyproject.toml | 2 +- tests/test_model_definition/test_aliases.py | 39 +- tests/test_model_definition/test_columns.py | 29 +- .../test_create_uses_init_for_consistency.py | 14 +- .../test_dates_with_timezone.py | 35 +- .../test_equality_and_hash.py | 9 +- .../test_extra_ignore_parameter.py | 11 +- .../test_fields_access.py | 27 +- ...oreign_key_value_used_for_related_model.py | 19 +- tests/test_model_definition/test_iterate.py | 36 +- .../test_model_construct.py | 36 +- .../test_model_definition.py | 91 +- tests/test_model_definition/test_models.py | 216 +-- .../test_models_are_pickable.py | 18 +- .../test_overwriting_pydantic_field_type.py | 20 +- .../test_overwriting_sql_nullable.py | 10 +- .../test_pk_field_is_always_not_null.py | 18 +- .../test_model_definition/test_properties.py | 9 +- .../test_pydantic_fields.py | 19 +- .../test_pydantic_only_fields.py | 9 +- .../test_pydantic_private_attributes.py | 10 +- .../test_model_definition/test_save_status.py | 36 +- .../test_saving_nullable_fields.py | 18 +- .../test_server_default.py | 17 +- .../test_setting_comments_in_db.py | 13 +- tests/test_types.py | 16 +- 63 files changed, 1582 insertions(+), 1535 deletions(-) create mode 100644 ormar/models/ormar_config.py diff --git a/ormar/__init__.py b/ormar/__init__.py index 9259d1d46..e4d3e1165 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -78,6 +78,7 @@ from ormar.queryset import OrderAction, QuerySet, and_, or_ from ormar.relations import RelationType from ormar.signals import Signal +from ormar.models import OrmarConfig class UndefinedType: # pragma no cover diff --git a/ormar/fields/base.py b/ormar/fields/base.py index cb320cf6d..40c47f1dd 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -3,7 +3,7 @@ import sqlalchemy from pydantic import typing -from pydantic.fields import FieldInfo, _Undefined +from pydantic.fields import FieldInfo, _Unset import ormar # noqa I101 from ormar import ModelDefinitionError @@ -145,7 +145,7 @@ def get_pydantic_default(self) -> Dict: """ base = self.default_value() if base is None: - base = dict(default=None) if self.nullable else dict(default=_Undefined) + base = dict(default=None) if self.nullable else dict(default=_Unset) return base def default_value(self, use_server: bool = False) -> Optional[Dict]: @@ -244,8 +244,8 @@ def construct_constraints(self) -> List: con.reference, ondelete=con.ondelete, onupdate=con.onupdate, - name=f"fk_{self.owner.Meta.tablename}_{self.to.Meta.tablename}" - f"_{self.to.get_column_alias(self.to.Meta.pkname)}_{self.name}", + name=f"fk_{self.owner.ormar_config.tablename}_{self.to.ormar_config.tablename}" + f"_{self.to.get_column_alias(self.to.ormar_config.pkname)}_{self.name}", ) for con in self.constraints ] @@ -339,7 +339,7 @@ def set_self_reference_flag(self) -> None: :rtype: None """ if self.owner is not None and ( - self.owner == self.to or self.owner.Meta == self.to.Meta + self.owner == self.to or self.owner.ormar_config == self.to.ormar_config ): self.self_reference = True self.self_reference_primary = self.name diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index 102597b14..c656862f5 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -15,7 +15,6 @@ overload, ) -from pydantic._internal._typing_extra import evaluate_fwd_ref import ormar # noqa I101 import sqlalchemy @@ -49,10 +48,10 @@ def create_dummy_instance(fk: Type["T"], pk: Any = None) -> "T": :rtype: Model """ init_dict = { - **{fk.Meta.pkname: pk or -1, "__pk_only__": True}, + **{fk.ormar_config.pkname: pk or -1, "__pk_only__": True}, **{ k: create_dummy_instance(v.to) - for k, v in fk.Meta.model_fields.items() + for k, v in fk.ormar_config.model_fields.items() if v.is_relation and not v.nullable and not v.virtual }, } @@ -107,8 +106,10 @@ def populate_fk_params_based_on_to_model( :return: tuple with target pydantic type, list of fk constraints and target col type :rtype: Tuple[Any, List, Any] """ - fk_string = to.Meta.tablename + "." + to.get_column_alias(to.Meta.pkname) - to_field = to.Meta.model_fields[to.Meta.pkname] + fk_string = ( + to.ormar_config.tablename + "." + to.get_column_alias(to.ormar_config.pkname) + ) + to_field = to.ormar_config.model_fields[to.ormar_config.pkname] pk_only_model = create_dummy_model(to, to_field) __type__ = ( Union[to_field.__type__, to, pk_only_model] @@ -366,9 +367,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = evaluate_fwd_ref( - self.to, globalns, localns or None # type: ignore - ) + self.to.model_rebuild(force=True) ( self.__type__, self.constraints, @@ -446,7 +445,10 @@ def _construct_model_from_dict( :return: (if needed) registered Model :rtype: Model """ - if len(value.keys()) == 1 and list(value.keys())[0] == self.to.Meta.pkname: + if ( + len(value.keys()) == 1 + and list(value.keys())[0] == self.to.ormar_config.pkname + ): value["__pk_only__"] = True model = self.to(**value) if to_register: diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index e69bfdcd6..30ff2c271 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -12,7 +12,6 @@ overload, ) -from pydantic._internal._typing_extra import evaluate_fwd_ref import ormar # noqa: I100 from ormar import ModelDefinitionError from ormar.fields import BaseField @@ -37,7 +36,7 @@ def forbid_through_relations(through: Type["Model"]) -> None: :param through: through Model to be checked :type through: Type['Model] """ - if any(field.is_relation for field in through.Meta.model_fields.values()): + if any(field.is_relation for field in through.ormar_config.model_fields.values()): raise ModelDefinitionError( f"Through Models cannot have explicit relations " f"defined. Remove the relations from Model " @@ -59,7 +58,7 @@ def populate_m2m_params_based_on_to_model( :return: Tuple[List, Any] :rtype: tuple with target pydantic type and target col type """ - to_field = to.Meta.model_fields[to.Meta.pkname] + to_field = to.ormar_config.model_fields[to.ormar_config.pkname] __type__ = ( Union[to_field.__type__, to, List[to]] # type: ignore if not nullable @@ -195,7 +194,7 @@ def get_source_related_name(self) -> str: :rtype: str """ return ( - self.through.Meta.model_fields[ + self.through.ormar_config.model_fields[ self.default_source_field_name() ].related_name or self.name @@ -223,18 +222,14 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = evaluate_fwd_ref( - self.to, globalns, localns or None # type: ignore - ) + self.to.model_rebuild(force=True) (self.__type__, self.column_type) = populate_m2m_params_based_on_to_model( to=self.to, nullable=self.nullable ) if self.through.__class__ == ForwardRef: - self.through = evaluate_fwd_ref( - self.through, globalns, localns or None # type: ignore - ) + self.through.model_rebuild(force=True) forbid_through_relations(self.through) def get_relation_name(self) -> str: @@ -266,15 +261,23 @@ def create_default_through_model(self) -> None: to_name = self.to.get_name(lower=False) class_name = f"{owner_name}{to_name}" table_name = f"{owner_name.lower()}s_{to_name.lower()}s" + base_namespace = { + "__module__": self.owner.__module__, + "__qualname__": f"{self.owner.__qualname__}.{class_name}", + } new_meta_namespace = { "tablename": table_name, - "database": self.owner.Meta.database, - "metadata": self.owner.Meta.metadata, + "database": self.owner.ormar_config.database, + "metadata": self.owner.ormar_config.metadata, } - new_meta = type("Meta", (), new_meta_namespace) + new_meta = ormar.models.ormar_config.OrmarConfig(**new_meta_namespace) through_model = type( class_name, (ormar.Model,), - {"Meta": new_meta, "id": ormar.Integer(name="id", primary_key=True)}, + { + **base_namespace, + "ormar_config": new_meta, + "id": ormar.Integer(name="id", primary_key=True), + }, ) self.through = cast(Type["Model"], through_model) diff --git a/ormar/fields/model_fields.py b/ormar/fields/model_fields.py index f2f4cfc3b..16ab80c76 100644 --- a/ormar/fields/model_fields.py +++ b/ormar/fields/model_fields.py @@ -62,49 +62,6 @@ def is_auto_primary_key(primary_key: bool, autoincrement: bool) -> bool: return primary_key and autoincrement -def convert_choices_if_needed( - field_type: "Type", - choices: Set, - nullable: bool, - scale: int = None, - represent_as_str: bool = False, -) -> Set: - """ - Converts dates to isoformat as fastapi can check this condition in routes - and the fields are not yet parsed. - Converts enums to list of it's values. - Converts uuids to strings. - Converts decimal to float with given scale. - - :param field_type: type o the field - :type field_type: Type - :param choices: set of choices - :type choices: Set - :param scale: scale for decimals - :type scale: int - :param nullable: flag if field_nullable - :type nullable: bool - :param represent_as_str: flag for bytes fields - :type represent_as_str: bool - :param scale: scale for decimals - :type scale: int - :return: value, choices list - :rtype: Tuple[Any, Set] - """ - choices = {o.value if isinstance(o, E) else o for o in choices} - encoder = ormar.ENCODERS_MAP.get(field_type, lambda x: x) - if field_type == decimal.Decimal: - precision = scale - choices = {encoder(o, precision) for o in choices} - elif field_type == bytes: - choices = {encoder(o, represent_as_str) for o in choices} - elif encoder: - choices = {encoder(o) for o in choices} - if nullable: - choices.add(None) - return choices - - class ModelFieldFactory: """ Default field factory that construct Field classes and populated their values. @@ -141,15 +98,6 @@ def __new__(cls, *args: Any, **kwargs: Any) -> BaseField: # type: ignore else (nullable if sql_nullable is None else sql_nullable) ) - choices = set(kwargs.pop("choices", [])) - if choices: - choices = convert_choices_if_needed( - field_type=cls._type, - choices=choices, - nullable=nullable, - scale=kwargs.get("scale", None), - represent_as_str=kwargs.get("represent_as_base64_str", False), - ) enum_class = kwargs.pop("enum_class", None) field_type = cls._type if enum_class is None else enum_class @@ -173,7 +121,6 @@ def __new__(cls, *args: Any, **kwargs: Any) -> BaseField: # type: ignore column_type=cls.get_column_type( **kwargs, sql_nullable=sql_nullable, enum_class=enum_class ), - choices=choices, encrypt_secret=encrypt_secret, encrypt_backend=encrypt_backend, encrypt_custom_backend=encrypt_custom_backend, diff --git a/ormar/models/__init__.py b/ormar/models/__init__.py index 1bac952c0..fa7bf845c 100644 --- a/ormar/models/__init__.py +++ b/ormar/models/__init__.py @@ -9,5 +9,14 @@ from ormar.models.model import Model, T # noqa I100 from ormar.models.excludable import ExcludableItems # noqa I100 from ormar.models.utils import Extra # noqa I100 +from ormar.models.ormar_config import OrmarConfig # noqa I100 -__all__ = ["NewBaseModel", "Model", "ModelRow", "ExcludableItems", "T", "Extra"] +__all__ = [ + "NewBaseModel", + "Model", + "ModelRow", + "ExcludableItems", + "T", + "Extra", + "OrmarConfig", +] diff --git a/ormar/models/descriptors/descriptors.py b/ormar/models/descriptors/descriptors.py index 35f419470..dde90b4e2 100644 --- a/ormar/models/descriptors/descriptors.py +++ b/ormar/models/descriptors/descriptors.py @@ -53,7 +53,7 @@ def __init__(self, name: str) -> None: def __get__(self, instance: "Model", owner: Type["Model"]) -> Any: value = instance.__dict__.get(self.name, None) - field = instance.Meta.model_fields[self.name] + field = instance.ormar_config.model_fields[self.name] if ( value is not None and field.represent_as_base64_str @@ -63,7 +63,7 @@ def __get__(self, instance: "Model", owner: Type["Model"]) -> Any: return value def __set__(self, instance: "Model", value: Any) -> None: - field = instance.Meta.model_fields[self.name] + field = instance.ormar_config.model_fields[self.name] if isinstance(value, str): if field.represent_as_base64_str: value = base64.b64decode(value) @@ -107,7 +107,7 @@ def __get__(self, instance: "Model", owner: Type["Model"]) -> Any: return None # pragma no cover def __set__(self, instance: "Model", value: Any) -> None: - model = instance.Meta.model_fields[self.name].expand_relationship( + model = instance.ormar_config.model_fields[self.name].expand_relationship( value=value, child=instance ) if isinstance(instance.__dict__.get(self.name), list): diff --git a/ormar/models/helpers/__init__.py b/ormar/models/helpers/__init__.py index 0d9e6ce77..f9a725ca1 100644 --- a/ormar/models/helpers/__init__.py +++ b/ormar/models/helpers/__init__.py @@ -1,7 +1,7 @@ from ormar.models.helpers.models import ( check_required_meta_parameters, extract_annotations_and_default_vals, - meta_field_not_set, + config_field_not_set, populate_default_options_values, ) from ormar.models.helpers.pydantic import ( @@ -21,7 +21,7 @@ populate_meta_tablename_columns_and_pk, sqlalchemy_columns_from_model_fields, ) -from ormar.models.helpers.validation import populate_choices_validators +from ormar.models.helpers.validation import modify_schema_example __all__ = [ "expand_reverse_relationships", @@ -37,7 +37,7 @@ "merge_or_generate_pydantic_config", "check_required_meta_parameters", "sqlalchemy_columns_from_model_fields", - "populate_choices_validators", - "meta_field_not_set", + "config_field_not_set", "remove_excluded_parent_fields", + "modify_schema_example", ] diff --git a/ormar/models/helpers/models.py b/ormar/models/helpers/models.py index 9a106346e..25e93158c 100644 --- a/ormar/models/helpers/models.py +++ b/ormar/models/helpers/models.py @@ -11,6 +11,7 @@ if TYPE_CHECKING: # pragma no cover from ormar import Model from ormar.fields import BaseField + from ormar.queryset import QuerySet def is_field_an_forward_ref(field: "BaseField") -> bool: @@ -46,35 +47,15 @@ def populate_default_options_values( # noqa: CCR001 :param model_fields: dict of model fields :type model_fields: Union[Dict[str, type], Dict] """ - defaults = { - "queryset_class": ormar.QuerySet, - "constraints": [], - "model_fields": model_fields, - "abstract": False, - "extra": Extra.forbid, - "orders_by": [], - "exclude_parent_fields": [], - } - for key, value in defaults.items(): - if not hasattr(new_model.Meta, key): - setattr(new_model.Meta, key, value) - - if any( - is_field_an_forward_ref(field) for field in new_model.Meta.model_fields.values() - ): - new_model.Meta.requires_ref_update = True - else: - new_model.Meta.requires_ref_update = False + new_model.ormar_config.model_fields = model_fields + if any(is_field_an_forward_ref(field) for field in model_fields.values()): + new_model.ormar_config.requires_ref_update = True new_model._json_fields = { - name - for name, field in new_model.Meta.model_fields.items() - if field.__type__ == pydantic.Json + name for name, field in model_fields.items() if field.__type__ == pydantic.Json } new_model._bytes_fields = { - name - for name, field in new_model.Meta.model_fields.items() - if field.__type__ == bytes + name for name, field in model_fields.items() if field.__type__ == bytes } new_model.__relation_map__ = None @@ -94,7 +75,7 @@ def substitue_backend_pool_for_sqlite(new_model: Type["Model"]) -> None: :param new_model: newly declared ormar Model :type new_model: Model class """ - backend = new_model.Meta.database._backend + backend = new_model.ormar_config.database._backend if ( backend._dialect.name == "sqlite" and "factory" not in backend._options ): # pragma: no cover @@ -112,20 +93,17 @@ def check_required_meta_parameters(new_model: Type["Model"]) -> None: :param new_model: newly declared ormar Model :type new_model: Model class """ - if not hasattr(new_model.Meta, "database"): - if not getattr(new_model.Meta, "abstract", False): - raise ormar.ModelDefinitionError( - f"{new_model.__name__} does not have database defined." - ) - + if new_model.ormar_config.database is None and not new_model.ormar_config.abstract: + raise ormar.ModelDefinitionError( + f"{new_model.__name__} does not have database defined." + ) else: substitue_backend_pool_for_sqlite(new_model=new_model) - if not hasattr(new_model.Meta, "metadata"): - if not getattr(new_model.Meta, "abstract", False): - raise ormar.ModelDefinitionError( - f"{new_model.__name__} does not have metadata defined." - ) + if new_model.ormar_config.metadata is None and not new_model.ormar_config.abstract: + raise ormar.ModelDefinitionError( + f"{new_model.__name__} does not have metadata defined." + ) def extract_annotations_and_default_vals(attrs: Dict) -> Tuple[Dict, Dict]: @@ -176,7 +154,7 @@ def group_related_list(list_: List) -> Dict: return dict(sorted(result_dict.items(), key=lambda item: len(item[1]))) -def meta_field_not_set(model: Type["Model"], field_name: str) -> bool: +def config_field_not_set(model: Type["Model"], field_name: str) -> bool: """ Checks if field with given name is already present in model.Meta. Then check if it's set to something truthful @@ -189,4 +167,4 @@ def meta_field_not_set(model: Type["Model"], field_name: str) -> bool: :return: result of the check :rtype: bool """ - return not hasattr(model.Meta, field_name) or not getattr(model.Meta, field_name) + return not getattr(model.ormar_config, field_name) diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index 8ab208d9d..725db1aa9 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -6,6 +6,7 @@ from pydantic import ConfigDict from pydantic.fields import Field from pydantic.utils import lenient_issubclass +from pydantic_core import PydanticUndefined from ormar.exceptions import ModelDefinitionError # noqa: I100, I202 from ormar.fields import BaseField @@ -34,7 +35,7 @@ def create_pydantic_field( model_field.through.__fields__[field_name] = Field( name=field_name, type_=model, - model_config=model.__config__, + model_config=model.model_config, required=False, class_validators={}, ) @@ -52,12 +53,14 @@ def get_pydantic_field(field_name: str, model: Type["Model"]) -> "Field": :return: newly created pydantic field :rtype: pydantic.Field """ - type_ = model.Meta.model_fields[field_name].__type__ + type_ = model.ormar_config.model_fields[field_name].__type__ return Field( name=field_name, type_=type_, # type: ignore - model_config=model.__config__, - required=not model.Meta.model_fields[field_name].nullable, + model_config=model.model_config, + default=None + if model.ormar_config.model_fields[field_name].nullable + else PydanticUndefined, class_validators={}, ) @@ -156,7 +159,9 @@ def remove_excluded_parent_fields(model: Type["Model"]) -> None: :param model: :type model: Type["Model"] """ - excludes = {*model.Meta.exclude_parent_fields} - {*model.Meta.model_fields.keys()} + excludes = {*model.ormar_config.exclude_parent_fields} - { + *model.ormar_config.model_fields.keys() + } if excludes: model.__fields__ = { k: v for k, v in model.__fields__.items() if k not in excludes diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index c6d1ba466..2b0c9b746 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -82,7 +82,7 @@ def expand_reverse_relationships(model: Type["Model"]) -> None: :param model: model on which relation should be checked and registered :type model: Model class """ - model_fields = list(model.Meta.model_fields.values()) + model_fields = list(model.ormar_config.model_fields.values()) for model_field in model_fields: if model_field.is_relation and not model_field.has_unresolved_forward_refs(): model_field = cast("ForeignKeyField", model_field) @@ -103,7 +103,7 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: related_name = model_field.get_related_name() # TODO: Reverse relations does not register pydantic fields? if model_field.is_multi: - model_field.to.Meta.model_fields[related_name] = ManyToMany( # type: ignore + model_field.to.ormar_config.model_fields[related_name] = ManyToMany( # type: ignore model_field.owner, through=model_field.through, name=related_name, @@ -122,7 +122,7 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: register_through_shortcut_fields(model_field=model_field) adjust_through_many_to_many_model(model_field=model_field) else: - model_field.to.Meta.model_fields[related_name] = ForeignKey( # type: ignore + model_field.to.ormar_config.model_fields[related_name] = ForeignKey( # type: ignore model_field.owner, real_name=related_name, virtual=True, @@ -147,7 +147,7 @@ def register_through_shortcut_fields(model_field: "ManyToManyField") -> None: through_name = through_model.get_name(lower=True) related_name = model_field.get_related_name() - model_field.owner.Meta.model_fields[through_name] = Through( + model_field.owner.ormar_config.model_fields[through_name] = Through( through_model, real_name=through_name, virtual=True, @@ -156,7 +156,7 @@ def register_through_shortcut_fields(model_field: "ManyToManyField") -> None: nullable=True, ) - model_field.to.Meta.model_fields[through_name] = Through( + model_field.to.ormar_config.model_fields[through_name] = Through( through_model, real_name=through_name, virtual=True, @@ -209,10 +209,13 @@ def verify_related_name_dont_duplicate( :return: None :rtype: None """ - fk_field = model_field.to.Meta.model_fields.get(related_name) + fk_field = model_field.to.ormar_config.model_fields.get(related_name) if not fk_field: # pragma: no cover return - if fk_field.to != model_field.owner and fk_field.to.Meta != model_field.owner.Meta: + if ( + fk_field.to != model_field.owner + and fk_field.to.ormar_config != model_field.owner.ormar_config + ): raise ormar.ModelDefinitionError( f"Relation with related_name " f"'{related_name}' " @@ -237,8 +240,10 @@ def reverse_field_not_already_registered(model_field: "ForeignKeyField") -> bool :rtype: bool """ related_name = model_field.get_related_name() - check_result = related_name not in model_field.to.Meta.model_fields - check_result2 = model_field.owner.get_name() not in model_field.to.Meta.model_fields + check_result = related_name not in model_field.to.ormar_config.model_fields + check_result2 = ( + model_field.owner.get_name() not in model_field.to.ormar_config.model_fields + ) if not check_result: verify_related_name_dont_duplicate( diff --git a/ormar/models/helpers/sqlalchemy.py b/ormar/models/helpers/sqlalchemy.py index 537f8be8d..c46223518 100644 --- a/ormar/models/helpers/sqlalchemy.py +++ b/ormar/models/helpers/sqlalchemy.py @@ -14,6 +14,7 @@ if TYPE_CHECKING: # pragma no cover from ormar import Model, ModelMeta, ManyToManyField, BaseField, ForeignKeyField from ormar.models import NewBaseModel + from ormar.models.ormar_config import OrmarConfig def adjust_through_many_to_many_model(model_field: "ManyToManyField") -> None: @@ -28,7 +29,7 @@ def adjust_through_many_to_many_model(model_field: "ManyToManyField") -> None: """ parent_name = model_field.default_target_field_name() child_name = model_field.default_source_field_name() - model_fields = model_field.through.Meta.model_fields + model_fields = model_field.through.ormar_config.model_fields model_fields[parent_name] = ormar.ForeignKey( # type: ignore model_field.to, real_name=parent_name, @@ -72,8 +73,10 @@ def create_and_append_m2m_fk( :param model_field: field with ManyToMany relation :type model_field: ManyToManyField field """ - pk_alias = model.get_column_alias(model.Meta.pkname) - pk_column = next((col for col in model.Meta.columns if col.name == pk_alias), None) + pk_alias = model.get_column_alias(model.ormar_config.pkname) + pk_column = next( + (col for col in model.ormar_config.columns if col.name == pk_alias), None + ) if pk_column is None: # pragma: no cover raise ormar.ModelDefinitionError( "ManyToMany relation cannot lead to field without pk" @@ -82,15 +85,15 @@ def create_and_append_m2m_fk( field_name, pk_column.type, sqlalchemy.schema.ForeignKey( - model.Meta.tablename + "." + pk_alias, + model.ormar_config.tablename + "." + pk_alias, ondelete="CASCADE", onupdate="CASCADE", - name=f"fk_{model_field.through.Meta.tablename}_{model.Meta.tablename}" + name=f"fk_{model_field.through.ormar_config.tablename}_{model.ormar_config.tablename}" f"_{field_name}_{pk_alias}", ), ) - model_field.through.Meta.columns.append(column) - model_field.through.Meta.table.append_column(column) + model_field.through.ormar_config.columns.append(column) + model_field.through.ormar_config.table.append_column(column) def check_pk_column_validity( @@ -152,7 +155,7 @@ def sqlalchemy_columns_from_model_fields( if len(model_fields.keys()) == 0: model_fields["id"] = ormar.Integer(name="id", primary_key=True) logging.warning( - f"Table {new_model.Meta.tablename} had no fields so auto " + f"Table {new_model.ormar_config.tablename} had no fields so auto " "Integer primary key named `id` created." ) validate_related_names_in_relations(model_fields, new_model) @@ -240,31 +243,33 @@ def populate_meta_tablename_columns_and_pk( :rtype: ormar.models.metaclass.ModelMetaclass """ tablename = name.lower() + "s" - new_model.Meta.tablename = ( - new_model.Meta.tablename if hasattr(new_model.Meta, "tablename") else tablename + new_model.ormar_config.tablename = ( + new_model.ormar_config.tablename + if new_model.ormar_config.tablename + else tablename ) pkname: Optional[str] - if hasattr(new_model.Meta, "columns"): - columns = new_model.Meta.columns - pkname = new_model.Meta.pkname + if new_model.ormar_config.columns: + columns = new_model.ormar_config.columns + pkname = new_model.ormar_config.pkname else: pkname, columns = sqlalchemy_columns_from_model_fields( - new_model.Meta.model_fields, new_model + new_model.ormar_config.model_fields, new_model ) if pkname is None: raise ormar.ModelDefinitionError("Table has to have a primary key.") - new_model.Meta.columns = columns - new_model.Meta.pkname = pkname - if not new_model.Meta.orders_by: + new_model.ormar_config.columns = columns + new_model.ormar_config.pkname = pkname + if not new_model.ormar_config.orders_by: # by default we sort by pk name if other option not provided - new_model.Meta.orders_by.append(pkname) + new_model.ormar_config.orders_by.append(pkname) return new_model -def check_for_null_type_columns_from_forward_refs(meta: "ModelMeta") -> bool: +def check_for_null_type_columns_from_forward_refs(meta: "OrmarConfig") -> bool: """ Check is any column is of NUllType() meaning it's empty column from ForwardRef @@ -278,7 +283,7 @@ def check_for_null_type_columns_from_forward_refs(meta: "ModelMeta") -> bool: ) -def populate_meta_sqlalchemy_table_if_required(meta: "ModelMeta") -> None: +def populate_meta_sqlalchemy_table_if_required(meta: "OrmarConfig") -> None: """ Constructs sqlalchemy table out of columns and parameters set on Meta class. It populates name, metadata, columns and constraints. @@ -286,9 +291,7 @@ def populate_meta_sqlalchemy_table_if_required(meta: "ModelMeta") -> None: :param meta: Meta class of the Model without sqlalchemy table constructed :type meta: Model class Meta """ - if not hasattr(meta, "table") and check_for_null_type_columns_from_forward_refs( - meta - ): + if not meta.table and check_for_null_type_columns_from_forward_refs(meta): set_constraint_names(meta=meta) table = sqlalchemy.Table( meta.tablename, meta.metadata, *meta.columns, *meta.constraints @@ -296,7 +299,7 @@ def populate_meta_sqlalchemy_table_if_required(meta: "ModelMeta") -> None: meta.table = table -def set_constraint_names(meta: "ModelMeta") -> None: +def set_constraint_names(meta: "OrmarConfig") -> None: """ Populates the names on IndexColumns and UniqueColumns and CheckColumns constraints. @@ -335,7 +338,7 @@ def update_column_definition( :return: None :rtype: None """ - columns = model.Meta.columns + columns = model.ormar_config.columns for ind, column in enumerate(columns): if column.name == field.get_alias(): new_column = field.get_column(field.get_alias()) diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 007d8373e..5b2b91055 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -12,7 +12,7 @@ Union, ) -from pydantic import model_validator, typing +from pydantic import BeforeValidator, typing try: import orjson as json @@ -23,7 +23,7 @@ from pydantic.fields import Field import ormar # noqa: I100, I202 -from ormar.models.helpers.models import meta_field_not_set +from ormar.models.helpers.models import config_field_not_set from ormar.queryset.utils import translate_list_to_dict if TYPE_CHECKING: # pragma no cover @@ -31,19 +31,6 @@ from ormar.fields import BaseField -def check_if_field_has_choices(field: "BaseField") -> bool: - """ - Checks if given field has choices populated. - A if it has one, a validator for this field needs to be attached. - - :param field: ormar field to check - :type field: BaseField - :return: result of the check - :rtype: bool - """ - return hasattr(field, "choices") and bool(field.choices) - - def convert_value_if_needed(field: "BaseField", value: Any) -> Any: """ Converts dates to isoformat as fastapi can check this condition in routes @@ -71,31 +58,6 @@ def convert_value_if_needed(field: "BaseField", value: Any) -> Any: return value -def generate_validator(ormar_field: "BaseField") -> Callable: - choices = ormar_field.choices - - def validate_choices(cls: type, value: Any, field: "Field") -> None: - """ - Validates if given value is in provided choices. - - :raises ValueError: If value is not in choices. - :param field:field to validate - :type field: BaseField - :param value: value of the field - :type value: Any - """ - adjusted_value = convert_value_if_needed(field=ormar_field, value=value) - if adjusted_value is not ormar.Undefined and adjusted_value not in choices: - raise ValueError( - f"{field.name}: '{adjusted_value}' " - f"not in allowed choices set:" - f" {choices}" - ) - return value - - return validate_choices - - def generate_model_example(model: Type["Model"], relation_map: Dict = None) -> Dict: """ Generates example to be included in schema in fastapi. @@ -295,7 +257,7 @@ def schema_extra(schema: Dict[str, Any], model: Type["Model"]) -> None: return staticmethod(schema_extra) # type: ignore -def populate_choices_validators(model: Type["Model"]) -> None: # noqa CCR001 +def modify_schema_example(model: Type["Model"]) -> None: # noqa CCR001 """ Checks if Model has any fields with choices set. If yes it adds choices validation into pre root validators. @@ -303,22 +265,5 @@ def populate_choices_validators(model: Type["Model"]) -> None: # noqa CCR001 :param model: newly constructed Model :type model: Model class """ - fields_with_choices = [] - if not meta_field_not_set(model=model, field_name="model_fields"): - if not hasattr(model, "_choices_fields"): - model._choices_fields = set() - for name, field in model.Meta.model_fields.items(): - if check_if_field_has_choices(field) and name not in model._choices_fields: - fields_with_choices.append(name) - validator = model_validator(mode="before")(generate_validator(field)) - model.__fields__[name].validators.append(validator) - model._choices_fields.add(name) - - if fields_with_choices: - model.Config.schema_extra = construct_modify_schema_function( - fields_with_choices=fields_with_choices - ) - else: - model.model_config[ - "schema_extra" - ] = construct_schema_function_without_choices() + if not config_field_not_set(model=model, field_name="model_fields"): + model.model_config["schema_extra"] = construct_schema_function_without_choices() diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 06027788e..20d63c067 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -15,6 +15,10 @@ import databases import pydantic import sqlalchemy +from pydantic._internal._model_construction import complete_model_class +from pydantic.fields import FieldInfo +from pydantic.plugin._schema_validator import create_schema_validator +from pydantic_core import SchemaSerializer from sqlalchemy.sql.schema import ColumnCollectionConstraint import ormar # noqa I100 @@ -34,22 +38,22 @@ ) from ormar.models.descriptors.descriptors import BytesDescriptor from ormar.models.helpers import ( - alias_manager, check_required_meta_parameters, expand_reverse_relationships, extract_annotations_and_default_vals, get_potential_fields, get_pydantic_field, merge_or_generate_pydantic_config, - meta_field_not_set, - populate_choices_validators, + config_field_not_set, populate_default_options_values, + modify_schema_example, populate_meta_sqlalchemy_table_if_required, populate_meta_tablename_columns_and_pk, register_relation_in_alias_manager, remove_excluded_parent_fields, sqlalchemy_columns_from_model_fields, ) +from ormar.models.ormar_config import OrmarConfig from ormar.models.quick_access_views import quick_access_set from ormar.models.utils import Extra from ormar.queryset import FieldAccessor, QuerySet @@ -108,7 +112,7 @@ def add_cached_properties(new_model: Type["Model"]) -> None: new_model._related_names = None new_model._through_names = None new_model._related_fields = None - new_model._pydantic_fields = {name for name in new_model.__fields__} + new_model._pydantic_fields = {name for name in new_model.model_fields.keys()} new_model._json_fields = set() new_model._bytes_fields = set() @@ -134,10 +138,12 @@ def add_property_fields(new_model: Type["Model"], attrs: Dict) -> None: # noqa: if field_config: props.add(var_name) - if meta_field_not_set(model=new_model, field_name="property_fields"): - new_model.Meta.property_fields = props + if config_field_not_set(model=new_model, field_name="property_fields"): + new_model.ormar_config.property_fields = props else: - new_model.Meta.property_fields = new_model.Meta.property_fields.union(props) + new_model.ormar_config.property_fields = ( + new_model.ormar_config.property_fields.union(props) + ) def register_signals(new_model: Type["Model"]) -> None: # noqa: CCR001 @@ -150,8 +156,8 @@ def register_signals(new_model: Type["Model"]) -> None: # noqa: CCR001 :param new_model: newly constructed model :type new_model: Model class """ - if meta_field_not_set(model=new_model, field_name="signals"): - signals = SignalEmitter() + if config_field_not_set(model=new_model, field_name="signals"): + signals = new_model.ormar_config.signals signals.pre_save = Signal() signals.pre_update = Signal() signals.pre_delete = Signal() @@ -163,7 +169,6 @@ def register_signals(new_model: Type["Model"]) -> None: # noqa: CCR001 signals.pre_relation_remove = Signal() signals.post_relation_remove = Signal() signals.post_bulk_update = Signal() - new_model.Meta.signals = signals def verify_constraint_names( @@ -446,7 +451,7 @@ def extract_from_parents_definition( # noqa: CCR001 :return: updated attrs and model_fields :rtype: Tuple[Dict, Dict] """ - if hasattr(base_class, "Meta"): + if hasattr(base_class, "ormar_config"): base_class = cast(Type["Model"], base_class) return copy_data_from_parent_model( base_class=base_class, @@ -593,42 +598,43 @@ def __new__( # type: ignore # noqa: CCR001 attrs, model_fields = extract_from_parents_definition( base_class=base, curr_class=mcs, attrs=attrs, model_fields=model_fields ) + if "ormar_config" in attrs: + attrs["model_config"]["ignored_types"] = (OrmarConfig,) new_model = super().__new__(mcs, name, bases, attrs) # type: ignore add_cached_properties(new_model) - if hasattr(new_model, "Meta"): + if hasattr(new_model, "ormar_config"): populate_default_options_values(new_model, model_fields) check_required_meta_parameters(new_model) add_property_fields(new_model, attrs) register_signals(new_model=new_model) - populate_choices_validators(new_model) + modify_schema_example(model=new_model) - if not new_model.Meta.abstract: + if not new_model.ormar_config.abstract: new_model = populate_meta_tablename_columns_and_pk(name, new_model) - populate_meta_sqlalchemy_table_if_required(new_model.Meta) + populate_meta_sqlalchemy_table_if_required(new_model.ormar_config) expand_reverse_relationships(new_model) # TODO: iterate only related fields - for field_name, field in new_model.Meta.model_fields.items(): + for field_name, field in new_model.ormar_config.model_fields.items(): register_relation_in_alias_manager(field=field) add_field_descriptor( name=field_name, field=field, new_model=new_model ) if ( - new_model.Meta.pkname - and new_model.Meta.pkname not in attrs["__annotations__"] - and new_model.Meta.pkname not in new_model.__fields__ + new_model.ormar_config.pkname + and new_model.ormar_config.pkname not in attrs["__annotations__"] + and new_model.ormar_config.pkname not in new_model.model_fields ): - field_name = new_model.Meta.pkname - attrs["__annotations__"][field_name] = Optional[int] # type: ignore - attrs[field_name] = None - new_model.__fields__[field_name] = get_pydantic_field( - field_name=field_name, model=new_model + field_name = new_model.ormar_config.pkname + new_model.model_fields[field_name] = FieldInfo.from_annotation( + Optional[int] ) - new_model.Meta.alias_manager = alias_manager + new_model.model_fields[field_name].default = None + new_model.model_rebuild(force=True) - for item in new_model.Meta.property_fields: + for item in new_model.ormar_config.property_fields: function = getattr(new_model, item) setattr( new_model, @@ -636,20 +642,20 @@ def __new__( # type: ignore # noqa: CCR001 PropertyDescriptor(name=item, function=function), ) - new_model.pk = PkDescriptor(name=new_model.Meta.pkname) + new_model.pk = PkDescriptor(name=new_model.ormar_config.pkname) remove_excluded_parent_fields(new_model) return new_model @property def objects(cls: Type["T"]) -> "QuerySet[T]": # type: ignore - if cls.Meta.requires_ref_update: + if cls.ormar_config.requires_ref_update: raise ModelError( f"Model {cls.get_name()} has not updated " f"ForwardRefs. \nBefore using the model you " f"need to call update_forward_refs()." ) - return cls.Meta.queryset_class(model_cls=cls) + return cls.ormar_config.queryset_class(model_cls=cls) def __getattr__(self, item: str) -> Any: """ @@ -662,9 +668,9 @@ def __getattr__(self, item: str) -> Any: :rtype: FieldAccessor """ if item == "pk": - item = self.Meta.pkname - if item in object.__getattribute__(self, "Meta").model_fields: - field = self.Meta.model_fields.get(item) + item = self.ormar_config.pkname + if item in object.__getattribute__(self, "ormar_config").model_fields: + field = self.ormar_config.model_fields.get(item) if field.is_relation: return FieldAccessor( source_model=cast(Type["Model"], self), diff --git a/ormar/models/mixins/alias_mixin.py b/ormar/models/mixins/alias_mixin.py index 2d9865736..c4b2b983d 100644 --- a/ormar/models/mixins/alias_mixin.py +++ b/ormar/models/mixins/alias_mixin.py @@ -7,9 +7,9 @@ class AliasMixin: """ if TYPE_CHECKING: # pragma: no cover - from ormar import ModelMeta + from ormar.models.ormar_config import OrmarConfig - Meta: ModelMeta + ormar_config: OrmarConfig @classmethod def get_column_alias(cls, field_name: str) -> str: @@ -21,7 +21,7 @@ def get_column_alias(cls, field_name: str) -> str: :return: alias (db name) if set, otherwise passed name :rtype: str """ - field = cls.Meta.model_fields.get(field_name) + field = cls.ormar_config.model_fields.get(field_name) return field.get_alias() if field is not None else field_name @classmethod @@ -34,7 +34,7 @@ def get_column_name_from_alias(cls, alias: str) -> str: :return: field name if set, otherwise passed alias (db name) :rtype: str """ - for field_name, field in cls.Meta.model_fields.items(): + for field_name, field in cls.ormar_config.model_fields.items(): if field.get_alias() == alias: return field_name return alias # if not found it's not an alias but actual name @@ -50,7 +50,7 @@ def translate_columns_to_aliases(cls, new_kwargs: Dict) -> Dict: :return: dict with aliases and their values :rtype: Dict """ - for field_name, field in cls.Meta.model_fields.items(): + for field_name, field in cls.ormar_config.model_fields.items(): if field_name in new_kwargs: new_kwargs[field.get_alias()] = new_kwargs.pop(field_name) return new_kwargs @@ -66,7 +66,7 @@ def translate_aliases_to_columns(cls, new_kwargs: Dict) -> Dict: :return: dict with fields names and their values :rtype: Dict """ - for field_name, field in cls.Meta.model_fields.items(): + for field_name, field in cls.ormar_config.model_fields.items(): if field.get_alias() and field.get_alias() in new_kwargs: new_kwargs[field_name] = new_kwargs.pop(field.get_alias()) return new_kwargs diff --git a/ormar/models/mixins/excludable_mixin.py b/ormar/models/mixins/excludable_mixin.py index d7019b735..f99996ca0 100644 --- a/ormar/models/mixins/excludable_mixin.py +++ b/ormar/models/mixins/excludable_mixin.py @@ -71,9 +71,9 @@ def _populate_pk_column( :rtype: List[str] """ pk_alias = ( - model.get_column_alias(model.Meta.pkname) + model.get_column_alias(model.ormar_config.pkname) if use_alias - else model.Meta.pkname + else model.ormar_config.pkname ) if pk_alias not in columns: columns.append(pk_alias) @@ -113,11 +113,11 @@ def own_table_columns( model_excludable = excludable.get(model_cls=model, alias=alias) # type: ignore columns = [ model.get_column_name_from_alias(col.name) if not use_alias else col.name - for col in model.Meta.table.columns + for col in model.ormar_config.table.columns ] field_names = [ model.get_column_name_from_alias(col.name) - for col in model.Meta.table.columns + for col in model.ormar_config.table.columns ] if model_excludable.include: columns = [ @@ -181,7 +181,7 @@ def _update_excluded_with_pks_and_through( :rtype: Set """ if exclude_primary_keys: - exclude.add(cls.Meta.pkname) + exclude.add(cls.ormar_config.pkname) if exclude_through_models: exclude = exclude.union(cls.extract_through_names()) return exclude @@ -219,6 +219,6 @@ def get_names_to_exclude(cls, excludable: ExcludableItems, alias: str) -> Set: fields_to_exclude = fields_to_exclude.union( model_excludable.exclude.intersection(fields_names) ) - fields_to_exclude = fields_to_exclude - {cls.Meta.pkname} + fields_to_exclude = fields_to_exclude - {cls.ormar_config.pkname} return fields_to_exclude diff --git a/ormar/models/mixins/relation_mixin.py b/ormar/models/mixins/relation_mixin.py index 3f9521c5c..0e6f4c107 100644 --- a/ormar/models/mixins/relation_mixin.py +++ b/ormar/models/mixins/relation_mixin.py @@ -10,9 +10,9 @@ class RelationMixin: """ if TYPE_CHECKING: # pragma no cover - from ormar import ModelMeta + from ormar.models.ormar_config import OrmarConfig - Meta: ModelMeta + ormar_config: OrmarConfig __relation_map__: Optional[List[str]] _related_names: Optional[Set] _through_names: Optional[Set] @@ -29,7 +29,9 @@ def extract_db_own_fields(cls) -> Set: """ related_names = cls.extract_related_names() self_fields = { - name for name in cls.Meta.model_fields.keys() if name not in related_names + name + for name in cls.ormar_config.model_fields.keys() + if name not in related_names } return self_fields @@ -47,7 +49,9 @@ def extract_related_fields(cls) -> List["ForeignKeyField"]: related_fields = [] for name in cls.extract_related_names().union(cls.extract_through_names()): - related_fields.append(cast("ForeignKeyField", cls.Meta.model_fields[name])) + related_fields.append( + cast("ForeignKeyField", cls.ormar_config.model_fields[name]) + ) cls._related_fields = related_fields return related_fields @@ -64,7 +68,7 @@ def extract_through_names(cls) -> Set[str]: return cls._through_names related_names = set() - for name, field in cls.Meta.model_fields.items(): + for name, field in cls.ormar_config.model_fields.items(): if isinstance(field, BaseField) and field.is_through: related_names.add(name) @@ -84,7 +88,7 @@ def extract_related_names(cls) -> Set[str]: return cls._related_names related_names = set() - for name, field in cls.Meta.model_fields.items(): + for name, field in cls.ormar_config.model_fields.items(): if ( isinstance(field, BaseField) and field.is_relation @@ -108,7 +112,7 @@ def _extract_db_related_names(cls) -> Set: related_names = { name for name in related_names - if cls.Meta.model_fields[name].is_valid_uni_relation() + if cls.ormar_config.model_fields[name].is_valid_uni_relation() } return related_names @@ -139,7 +143,7 @@ def _iterate_related_models( # noqa: CCR001 processed_relations: List[str] = [] for relation in relations: if not current_node.visited(relation): - target_model = cls.Meta.model_fields[relation].to + target_model = cls.ormar_config.model_fields[relation].to node_list.add( node_class=target_model, relation_name=relation, diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index 851e08551..5c73cd34c 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -96,7 +96,7 @@ def _remove_not_ormar_fields(cls, new_kwargs: dict) -> dict: :rtype: Dict[str, str] """ ormar_fields = { - k for k, v in cls.Meta.model_fields.items() if not v.pydantic_only + k for k, v in cls.ormar_config.model_fields.items() if not v.pydantic_only } new_kwargs = {k: v for k, v in new_kwargs.items() if k in ormar_fields} return new_kwargs @@ -112,8 +112,8 @@ def _remove_pk_from_kwargs(cls, new_kwargs: dict) -> dict: :return: dictionary of model that is about to be saved :rtype: Dict[str, str] """ - pkname = cls.Meta.pkname - pk = cls.Meta.model_fields[pkname] + pkname = cls.ormar_config.pkname + pk = cls.ormar_config.model_fields[pkname] if new_kwargs.get(pkname, ormar.Undefined) is None and ( pk.nullable or pk.autoincrement ): @@ -131,7 +131,7 @@ def parse_non_db_fields(cls, model_dict: Dict) -> Dict: :return: dictionary of model that is about to be saved :rtype: Dict """ - for name, field in cls.Meta.model_fields.items(): + for name, field in cls.ormar_config.model_fields.items(): if field.__type__ == uuid.UUID and name in model_dict: parsers = {"string": lambda x: str(x), "hex": lambda x: "%.32x" % x.int} uuid_format = field.column_type.uuid_format @@ -153,8 +153,8 @@ def substitute_models_with_pks(cls, model_dict: Dict) -> Dict: # noqa CCR001 for field in cls.extract_related_names(): field_value = model_dict.get(field, None) if field_value is not None: - target_field = cls.Meta.model_fields[field] - target_pkname = target_field.to.Meta.pkname + target_field = cls.ormar_config.model_fields[field] + target_pkname = target_field.to.ormar_config.pkname if isinstance(field_value, ormar.Model): # pragma: no cover pk_value = getattr(field_value, target_pkname) if not pk_value: @@ -187,7 +187,7 @@ def reconvert_str_to_bytes(cls, model_dict: Dict) -> Dict: """ bytes_base64_fields = { name - for name, field in cls.Meta.model_fields.items() + for name, field in cls.ormar_config.model_fields.items() if field.represent_as_base64_str } for key, value in model_dict.items(): @@ -227,7 +227,7 @@ def populate_default_values(cls, new_kwargs: Dict) -> Dict: :return: dictionary of model that is about to be saved :rtype: Dict """ - for field_name, field in cls.Meta.model_fields.items(): + for field_name, field in cls.ormar_config.model_fields.items(): if ( field_name not in new_kwargs and field.has_default(use_server=False) @@ -253,21 +253,7 @@ def validate_choices(cls, new_kwargs: Dict) -> Dict: :return: dictionary of model that is about to be saved :rtype: Dict """ - if not cls._choices_fields: - return new_kwargs - - fields_to_check = [ - field - for field in cls.Meta.model_fields.values() - if field.name in cls._choices_fields and field.name in new_kwargs - ] - for field in fields_to_check: - if new_kwargs[field.name] not in field.choices: - raise ValueError( - f"{field.name}: '{new_kwargs[field.name]}' " - f"not in allowed choices set:" - f" {field.choices}" - ) + cls.__pydantic_validator__.validate_python(new_kwargs) # type: ignore return new_kwargs @staticmethod @@ -329,7 +315,7 @@ async def _upsert_through_model( :param previous_model: previous model from which method came :type previous_model: Model """ - through_name = previous_model.Meta.model_fields[ + through_name = previous_model.ormar_config.model_fields[ relation_field.name ].through.get_name() through = getattr(instance, through_name) diff --git a/ormar/models/model.py b/ormar/models/model.py index 7ff8e6369..38a3b740a 100644 --- a/ormar/models/model.py +++ b/ormar/models/model.py @@ -3,7 +3,6 @@ import ormar.queryset # noqa I100 from ormar.exceptions import ModelPersistenceError, NoMatch from ormar.models import NewBaseModel # noqa I100 -from ormar.models.metaclass import ModelMeta from ormar.models.model_row import ModelRow from ormar.queryset.utils import subtract_dict, translate_list_to_dict @@ -11,17 +10,18 @@ if TYPE_CHECKING: # pragma: no cover from ormar import ForeignKeyField + from ormar.models.ormar_config import OrmarConfig class Model(ModelRow): __abstract__ = False if TYPE_CHECKING: # pragma nocover - Meta: ModelMeta + ormar_config: OrmarConfig def __repr__(self) -> str: # pragma nocover _repr = { k: getattr(self, k) - for k, v in self.Meta.model_fields.items() + for k, v in self.ormar_config.model_fields.items() if not v.skip_field } return f"{self.__class__.__name__}({str(_repr)})" @@ -40,8 +40,8 @@ async def upsert(self: T, **kwargs: Any) -> T: force_save = kwargs.pop("__force_save__", False) if force_save: - expr = self.Meta.table.select().where(self.pk_column == self.pk) - row = await self.Meta.database.fetch_one(expr) + expr = self.ormar_config.table.select().where(self.pk_column == self.pk) + row = await self.ormar_config.database.fetch_one(expr) if not row: return await self.save() return await self.update(**kwargs) @@ -76,8 +76,11 @@ async def save(self: T) -> T: await self.signals.pre_save.send(sender=self.__class__, instance=self) self_fields = self._extract_model_db_fields() - if not self.pk and self.Meta.model_fields[self.Meta.pkname].autoincrement: - self_fields.pop(self.Meta.pkname, None) + if ( + not self.pk + and self.ormar_config.model_fields[self.ormar_config.pkname].autoincrement + ): + self_fields.pop(self.ormar_config.pkname, None) self_fields = self.populate_default_values(self_fields) self.update_from_dict( { @@ -88,18 +91,18 @@ async def save(self: T) -> T: ) self_fields = self.translate_columns_to_aliases(self_fields) - expr = self.Meta.table.insert() + expr = self.ormar_config.table.insert() expr = expr.values(**self_fields) - pk = await self.Meta.database.execute(expr) + pk = await self.ormar_config.database.execute(expr) if pk and isinstance(pk, self.pk_type()): - setattr(self, self.Meta.pkname, pk) + setattr(self, self.ormar_config.pkname, pk) self.set_save_status(True) # refresh server side defaults if any( field.server_default is not None - for name, field in self.Meta.model_fields.items() + for name, field in self.ormar_config.model_fields.items() if name not in self_fields ): await self.load() @@ -240,14 +243,14 @@ async def update(self: T, _columns: List[str] = None, **kwargs: Any) -> T: sender=self.__class__, instance=self, passed_args=kwargs ) self_fields = self._extract_model_db_fields() - self_fields.pop(self.get_column_name_from_alias(self.Meta.pkname)) + self_fields.pop(self.get_column_name_from_alias(self.ormar_config.pkname)) if _columns: self_fields = {k: v for k, v in self_fields.items() if k in _columns} self_fields = self.translate_columns_to_aliases(self_fields) - expr = self.Meta.table.update().values(**self_fields) - expr = expr.where(self.pk_column == getattr(self, self.Meta.pkname)) + expr = self.ormar_config.table.update().values(**self_fields) + expr = expr.where(self.pk_column == getattr(self, self.ormar_config.pkname)) - await self.Meta.database.execute(expr) + await self.ormar_config.database.execute(expr) self.set_save_status(True) await self.signals.post_update.send(sender=self.__class__, instance=self) return self @@ -268,9 +271,9 @@ async def delete(self) -> int: :rtype: int """ await self.signals.pre_delete.send(sender=self.__class__, instance=self) - expr = self.Meta.table.delete() - expr = expr.where(self.pk_column == (getattr(self, self.Meta.pkname))) - result = await self.Meta.database.execute(expr) + expr = self.ormar_config.table.delete() + expr = expr.where(self.pk_column == (getattr(self, self.ormar_config.pkname))) + result = await self.ormar_config.database.execute(expr) self.set_save_status(False) await self.signals.post_delete.send(sender=self.__class__, instance=self) return result @@ -286,8 +289,8 @@ async def load(self: T) -> T: :return: reloaded Model :rtype: Model """ - expr = self.Meta.table.select().where(self.pk_column == self.pk) - row = await self.Meta.database.fetch_one(expr) + expr = self.ormar_config.table.select().where(self.pk_column == self.pk) + row = await self.ormar_config.database.fetch_one(expr) if not row: # pragma nocover raise NoMatch("Instance was deleted from database and cannot be refreshed") kwargs = dict(row) diff --git a/ormar/models/model_row.py b/ormar/models/model_row.py index e3cf6ec2e..aa524b5f0 100644 --- a/ormar/models/model_row.py +++ b/ormar/models/model_row.py @@ -97,7 +97,7 @@ def from_row( # noqa: CFQ002 ) instance: Optional["Model"] = None - if item.get(cls.Meta.pkname, None) is not None: + if item.get(cls.ormar_config.pkname, None) is not None: item["__excluded__"] = cls.get_names_to_exclude( excludable=excludable, alias=table_prefix ) @@ -130,11 +130,11 @@ def _process_table_prefix( previous_model = related_field.through else: previous_model = related_field.owner - table_prefix = cls.Meta.alias_manager.resolve_relation_alias( + table_prefix = cls.ormar_config.alias_manager.resolve_relation_alias( from_model=previous_model, relation_name=related_field.name ) if not table_prefix or table_prefix in used_prefixes: - manager = cls.Meta.alias_manager + manager = cls.ormar_config.alias_manager table_prefix = manager.resolve_relation_alias_after_complex( source_model=source_model, relation_str=current_relation_str, @@ -186,7 +186,7 @@ def _populate_nested_models_from_row( # noqa: CFQ002 """ for related in related_models: - field = cls.Meta.model_fields[related] + field = cls.ormar_config.model_fields[related] field = cast("ForeignKeyField", field) model_cls = field.to model_excludable = excludable.get( @@ -281,7 +281,7 @@ def _populate_through_instance( # noqa: CFQ002 :param proxy_source_model: source model from which querysetproxy is constructed :type proxy_source_model: Type["Model"] """ - through_name = cls.Meta.model_fields[related].through.get_name() + through_name = cls.ormar_config.model_fields[related].through.get_name() through_child = cls._create_through_instance( row=row, related=related, through_name=through_name, excludable=excludable ) @@ -315,8 +315,8 @@ def _create_through_instance( :return: initialized through model without relation :rtype: "ModelRow" """ - model_cls = cls.Meta.model_fields[through_name].to - table_prefix = cls.Meta.alias_manager.resolve_relation_alias( + model_cls = cls.ormar_config.model_fields[through_name].to + table_prefix = cls.ormar_config.alias_manager.resolve_relation_alias( from_model=cls, relation_name=related ) # remove relations on through field @@ -372,7 +372,7 @@ def extract_prefixed_table_columns( ) column_prefix = table_prefix + "_" if table_prefix else "" - for column in cls.Meta.table.columns: + for column in cls.ormar_config.table.columns: alias = cls.get_column_name_from_alias(column.name) if alias not in item and alias in selected_columns: prefixed_name = f"{column_prefix}{column.name}" diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 1df92254a..4193d2d15 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -23,6 +23,7 @@ import pydantic import sqlalchemy from pydantic import BaseModel +from pydantic_core import SchemaValidator import ormar # noqa I100 @@ -144,21 +145,18 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # type: ignore new_kwargs, through_tmp_dict = self._process_kwargs(kwargs) if not pk_only: - values, fields_set, validation_error = pydantic.validate_model( - self, new_kwargs # type: ignore + self.__pydantic_validator__.validate_python( + new_kwargs, self_instance=self # type: ignore ) - if validation_error: - raise validation_error else: - fields_set = {self.Meta.pkname} + fields_set = {self.ormar_config.pkname} values = new_kwargs - - object.__setattr__(self, "__dict__", values) - object.__setattr__(self, "__fields_set__", fields_set) + object.__setattr__(self, "__dict__", values) + object.__setattr__(self, "__pydantic_fields_set__", fields_set) # add back through fields new_kwargs.update(through_tmp_dict) - model_fields = object.__getattribute__(self, "Meta").model_fields + model_fields = object.__getattribute__(self, "ormar_config").model_fields # register the columns models after initialization for related in self.extract_related_names().union(self.extract_through_names()): model_fields[related].expand_relationship( @@ -189,7 +187,7 @@ def __setattr__(self, name: str, value: Any) -> None: # noqa CCR001 super().__setattr__(name, value) # In this case, the hash could have changed, so update it - if name == self.Meta.pkname or self.pk is None: + if name == self.ormar_config.pkname or self.pk is None: object.__setattr__(self, "__cached_hash__", None) new_hash = hash(self) @@ -198,16 +196,14 @@ def __setattr__(self, name: str, value: Any) -> None: # noqa CCR001 def __getattr__(self, item: str) -> Any: """ - Used only to silence mypy errors for Through models and reverse relations. - Not used in real life as in practice calls are intercepted - by RelationDescriptors + Used for private attributes of pydantic v2. :param item: name of attribute :type item: str :return: Any :rtype: Any """ - return super().__getattribute__(item) + return super().__getattr__(item) def __getstate__(self) -> Dict[Any, Any]: state = super().__getstate__() @@ -274,9 +270,9 @@ def _verify_model_can_be_initialized(self) -> None: :return: None :rtype: None """ - if self.Meta.abstract: + if self.ormar_config.abstract: raise ModelError(f"You cannot initialize abstract model {self.get_name()}") - if self.Meta.requires_ref_update: + if self.ormar_config.requires_ref_update: raise ModelError( f"Model {self.get_name()} has not updated " f"ForwardRefs. \nBefore using the model you " @@ -300,8 +296,8 @@ def _process_kwargs(self, kwargs: Dict) -> Tuple[Dict, Dict]: # noqa: CCR001 :return: modified kwargs :rtype: Tuple[Dict, Dict] """ - property_fields = self.Meta.property_fields - model_fields = self.Meta.model_fields + property_fields = self.ormar_config.property_fields + model_fields = self.ormar_config.model_fields pydantic_fields = set(self.__fields__.keys()) # remove property fields @@ -310,7 +306,7 @@ def _process_kwargs(self, kwargs: Dict) -> Tuple[Dict, Dict]: # noqa: CCR001 excluded: Set[str] = kwargs.pop("__excluded__", set()) if "pk" in kwargs: - kwargs[self.Meta.pkname] = kwargs.pop("pk") + kwargs[self.ormar_config.pkname] = kwargs.pop("pk") # extract through fields through_tmp_dict = dict() @@ -360,7 +356,7 @@ def _remove_extra_parameters_if_they_should_be_ignored( :return: dict without extra fields :rtype: Dict """ - if self.Meta.extra == Extra.ignore: + if self.ormar_config.extra == Extra.ignore: kwargs = { k: v for k, v in kwargs.items() @@ -475,7 +471,7 @@ def pk_column(self) -> sqlalchemy.Column: """ if object.__getattribute__(self, "_pk_column") is not None: return object.__getattribute__(self, "_pk_column") - pk_columns = self.Meta.table.primary_key.columns.values() + pk_columns = self.ormar_config.table.primary_key.columns.values() pk_col = pk_columns[0] object.__setattr__(self, "_pk_column", pk_col) return pk_col @@ -488,18 +484,18 @@ def saved(self) -> bool: @property def signals(self) -> "SignalEmitter": """Exposes signals from model Meta""" - return self.Meta.signals + return self.ormar_config.signals @classmethod def pk_type(cls) -> Any: """Shortcut to models primary key field type""" - return cls.Meta.model_fields[cls.Meta.pkname].__type__ + return cls.ormar_config.model_fields[cls.ormar_config.pkname].__type__ @classmethod def db_backend_name(cls) -> str: """Shortcut to database dialect, cause some dialect require different treatment""" - return cls.Meta.database._backend._dialect.name + return cls.ormar_config.database._backend._dialect.name def remove(self, parent: "Model", name: str) -> None: """Removes child from relation with given name in RelationshipManager""" @@ -528,7 +524,7 @@ def get_properties( :rtype: Set[str] """ - props = cls.Meta.property_fields + props = cls.ormar_config.property_fields if include: props = {prop for prop in props if prop in include} if exclude: @@ -557,7 +553,7 @@ def update_forward_refs(cls, **localns: Any) -> None: """ globalns = sys.modules[cls.__module__].__dict__.copy() globalns.setdefault(cls.__name__, cls) - fields_to_check = cls.Meta.model_fields.copy() + fields_to_check = cls.ormar_config.model_fields.copy() for field in fields_to_check.values(): if field.has_unresolved_forward_refs(): field = cast(ForeignKeyField, field) @@ -569,9 +565,9 @@ def update_forward_refs(cls, **localns: Any) -> None: expand_reverse_relationship(model_field=field) register_relation_in_alias_manager(field=field) update_column_definition(model=cls, field=field) - populate_meta_sqlalchemy_table_if_required(meta=cls.Meta) + populate_meta_sqlalchemy_table_if_required(meta=cls.ormar_config) super().update_forward_refs(**localns) - cls.Meta.requires_ref_update = False + cls.ormar_config.requires_ref_update = False @staticmethod def _get_not_excluded_fields( @@ -744,7 +740,6 @@ def dict( # type: ignore # noqa A003 include: Union[Set, Dict] = None, exclude: Union[Set, Dict] = None, by_alias: bool = False, - skip_defaults: bool = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, @@ -772,8 +767,6 @@ def dict( # type: ignore # noqa A003 :type exclude: Union[Set, Dict, None] :param by_alias: flag to get values by alias - passed to pydantic :type by_alias: bool - :param skip_defaults: flag to not set values - passed to pydantic - :type skip_defaults: bool :param exclude_unset: flag to exclude not set values - passed to pydantic :type exclude_unset: bool :param exclude_defaults: flag to exclude default values - passed to pydantic @@ -793,13 +786,12 @@ def dict( # type: ignore # noqa A003 exclude_primary_keys=exclude_primary_keys, exclude_through_models=exclude_through_models, ) - dict_instance = super().dict( + dict_instance = super().model_dump( include=include, exclude=pydantic_exclude, by_alias=by_alias, - skip_defaults=skip_defaults, - exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, + exclude_unset=exclude_unset, exclude_none=exclude_none, ) @@ -831,7 +823,7 @@ def dict( # type: ignore # noqa A003 ) # include model properties as fields in dict - if object.__getattribute__(self, "Meta").property_fields: + if object.__getattribute__(self, "ormar_config").property_fields: props = self.get_properties(include=include, exclude=exclude) if props: dict_instance.update({prop: getattr(self, prop) for prop in props}) @@ -844,11 +836,9 @@ def json( # type: ignore # noqa A003 include: Union[Set, Dict] = None, exclude: Union[Set, Dict] = None, by_alias: bool = False, - skip_defaults: bool = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, - encoder: Optional[Callable[[Any], Any]] = None, exclude_primary_keys: bool = False, exclude_through_models: bool = False, **dumps_kwargs: Any, @@ -860,14 +850,6 @@ def json( # type: ignore # noqa A003 `encoder` is an optional function to supply as `default` to json.dumps(), other arguments as per `json.dumps()`. """ - if skip_defaults is not None: # pragma: no cover - warnings.warn( - f'{self.__class__.__name__}.json(): "skip_defaults" is deprecated ' - f'and replaced by "exclude_unset"', - DeprecationWarning, - ) - exclude_unset = skip_defaults - encoder = cast(Callable[[Any], Any], encoder or self.__json_encoder__) data = self.dict( include=include, exclude=exclude, @@ -878,9 +860,7 @@ def json( # type: ignore # noqa A003 exclude_primary_keys=exclude_primary_keys, exclude_through_models=exclude_through_models, ) - if self.__custom_root_type__: # pragma: no cover - data = data["__root__"] - return self.__config__.json_dumps(data, default=encoder, **dumps_kwargs) + return self.__pydantic_serializer__.to_json(data).decode() @classmethod def construct( @@ -891,10 +871,10 @@ def construct( } model = cls.__new__(cls) fields_values: Dict[str, Any] = {} - for name, field in cls.__fields__.items(): + for name, field in cls.model_fields.items(): if name in own_values: fields_values[name] = own_values[name] - elif not field.required: + elif not field.is_required(): fields_values[name] = field.get_default() fields_values.update(own_values) object.__setattr__(model, "__dict__", fields_values) @@ -902,7 +882,7 @@ def construct( cls._construct_relations(model=model, values=values) if _fields_set is None: _fields_set = set(values.keys()) - object.__setattr__(model, "__fields_set__", _fields_set) + object.__setattr__(model, "__pydantic_fields_set__", _fields_set) return model @classmethod @@ -914,7 +894,7 @@ def _construct_relations(cls: Type["T"], model: "T", values: Dict) -> None: value_to_set = values[relation] if not isinstance(value_to_set, list): value_to_set = [value_to_set] - relation_field = cls.Meta.model_fields[relation] + relation_field = cls.ormar_config.model_fields[relation] relation_value = [ relation_field.expand_relationship(x, model, to_register=False) for x in value_to_set @@ -954,7 +934,7 @@ def _convert_to_bytes(self, column_name: str, value: Any) -> Union[str, Dict]: """ if column_name not in self._bytes_fields: return value - field = self.Meta.model_fields[column_name] + field = self.ormar_config.model_fields[column_name] if not isinstance(value, bytes) and value is not None: if field.represent_as_base64_str: value = base64.b64decode(value) @@ -975,7 +955,7 @@ def _convert_bytes_to_str(self, column_name: str, value: Any) -> Union[str, Dict """ if column_name not in self._bytes_fields: return value - field = self.Meta.model_fields[column_name] + field = self.ormar_config.model_fields[column_name] if ( value is not None and not isinstance(value, str) @@ -1026,11 +1006,11 @@ def _extract_model_db_fields(self) -> Dict: self_fields = { k: v for k, v in self_fields.items() - if self.get_column_alias(k) in self.Meta.table.columns + if self.get_column_alias(k) in self.ormar_config.table.columns } for field in self._extract_db_related_names(): - relation_field = self.Meta.model_fields[field] - target_pk_name = relation_field.to.Meta.pkname + relation_field = self.ormar_config.model_fields[field] + target_pk_name = relation_field.to.ormar_config.pkname target_field = getattr(self, field) self_fields[field] = getattr(target_field, target_pk_name, None) if not relation_field.nullable and not self_fields[field]: diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py new file mode 100644 index 000000000..efa0d94d2 --- /dev/null +++ b/ormar/models/ormar_config.py @@ -0,0 +1,67 @@ +from typing import Dict, List, Optional, Set, Type, Union + +import databases +import sqlalchemy +from sqlalchemy.sql.schema import ColumnCollectionConstraint + +from ormar import BaseField, ForeignKeyField, ManyToManyField +from ormar.models.helpers import alias_manager +from ormar.models.utils import Extra +from ormar.relations import AliasManager +from ormar.signals import SignalEmitter +from ormar.queryset.queryset import QuerySet + + +class OrmarConfig: + def __init__( + self, + metadata: Optional[sqlalchemy.MetaData] = None, + database: Optional[databases.Database] = None, + tablename: Optional[str] = None, + order_by: Optional[list[str]] = None, + abstract: bool = False, + exclude_parent_fields: Optional[List[str]] = None, + queryset_class: Type[QuerySet] = QuerySet, + extra: Extra = Extra.forbid, + ) -> None: + self.pkname: str = None + self.metadata = metadata + self.database = database + self.tablename = tablename + self.orders_by = order_by or [] + self.columns: List[sqlalchemy.Column] = [] + self.constraints: List[ColumnCollectionConstraint] = [] + self.model_fields: Dict[ + str, Union[BaseField, ForeignKeyField, ManyToManyField] + ] = {} + self.alias_manager: AliasManager = alias_manager + self.property_fields: Set = set() + self.signals: SignalEmitter = SignalEmitter() + self.abstract = abstract + self.requires_ref_update: bool = False + self.exclude_parent_fields = exclude_parent_fields or [] + self.extra = extra + self.queryset_class = queryset_class + self.table: sqlalchemy.Table = None + + def copy( + self, + metadata: Optional[sqlalchemy.MetaData] = None, + database: Optional[databases.Database] = None, + tablename: Optional[str] = None, + order_by: Optional[list[str]] = None, + abstract: Optional[bool] = None, + exclude_parent_fields: Optional[List[str]] = None, + queryset_class: Optional[Type[QuerySet]] = None, + extra: Optional[Extra] = None, + ) -> "OrmarConfig": + return OrmarConfig( + metadata=metadata or self.metadata, + database=database or self.database, + tablename=tablename, + order_by=order_by, + abstract=abstract, + exclude_parent_fields=exclude_parent_fields, + queryset_class=queryset_class or self.queryset_class, + extra=extra or self.extra, + ) diff --git a/ormar/models/quick_access_views.py b/ormar/models/quick_access_views.py index a82237589..0949c1baf 100644 --- a/ormar/models/quick_access_views.py +++ b/ormar/models/quick_access_views.py @@ -4,7 +4,7 @@ """ quick_access_set = { "Config", - "Meta", + "model_config", "__class__", "__config__", "__custom_root_type__", diff --git a/ormar/models/traversible.py b/ormar/models/traversible.py index 3a90bb925..8d4a527b7 100644 --- a/ormar/models/traversible.py +++ b/ormar/models/traversible.py @@ -108,7 +108,7 @@ def visited(self, relation_name: str) -> bool: :return: result of the check :rtype: bool """ - target_model = self.node_class.Meta.model_fields[relation_name].to + target_model = self.node_class.ormar_config.model_fields[relation_name].to if self.parent_node: node = self while node.parent_node: diff --git a/ormar/queryset/actions/filter_action.py b/ormar/queryset/actions/filter_action.py index e393333c1..dcc3636e8 100644 --- a/ormar/queryset/actions/filter_action.py +++ b/ormar/queryset/actions/filter_action.py @@ -143,8 +143,10 @@ def get_text_clause(self) -> sqlalchemy.sql.expression.BinaryExpression: else: filter_value = self.filter_value if self.table_prefix: - aliased_table = self.source_model.Meta.alias_manager.prefixed_table_name( - self.table_prefix, self.column.table + aliased_table = ( + self.source_model.ormar_config.alias_manager.prefixed_table_name( + self.table_prefix, self.column.table + ) ) aliased_column = getattr(aliased_table.c, self.column.name) else: diff --git a/ormar/queryset/actions/order_action.py b/ormar/queryset/actions/order_action.py index 7330d727f..458cdad7c 100644 --- a/ormar/queryset/actions/order_action.py +++ b/ormar/queryset/actions/order_action.py @@ -36,8 +36,10 @@ def field_alias(self) -> str: @property def is_postgres_bool(self) -> bool: - dialect = self.target_model.Meta.database._backend._dialect.name - field_type = self.target_model.Meta.model_fields[self.field_name].__type__ + dialect = self.target_model.ormar_config.database._backend._dialect.name + field_type = self.target_model.ormar_config.model_fields[ + self.field_name + ].__type__ return dialect == "postgresql" and field_type == bool def get_field_name_text(self) -> str: @@ -82,7 +84,7 @@ def get_text_clause(self) -> sqlalchemy.sql.expression.TextClause: table_name = self.table.name field_name = self.field_alias if not prefix: - dialect = self.target_model.Meta.database._backend._dialect + dialect = self.target_model.ormar_config.database._backend._dialect table_name = dialect.identifier_preparer.quote(table_name) field_name = dialect.identifier_preparer.quote(field_name) return text(f"{prefix}{table_name}" f".{field_name} {self.direction}") diff --git a/ormar/queryset/actions/query_action.py b/ormar/queryset/actions/query_action.py index 2c6ee8494..ec5f250bd 100644 --- a/ormar/queryset/actions/query_action.py +++ b/ormar/queryset/actions/query_action.py @@ -54,13 +54,13 @@ def get_text_clause( @property def table(self) -> sqlalchemy.Table: """Shortcut to sqlalchemy Table of filtered target model""" - return self.target_model.Meta.table + return self.target_model.ormar_config.table @property def column(self) -> sqlalchemy.Column: """Shortcut to sqlalchemy column of filtered target model""" aliased_name = self.target_model.get_column_alias(self.field_name) - return self.target_model.Meta.table.columns[aliased_name] + return self.target_model.ormar_config.table.columns[aliased_name] def update_select_related(self, select_related: List[str]) -> List[str]: """ diff --git a/ormar/queryset/clause.py b/ormar/queryset/clause.py index 2a86d454c..7fd093350 100644 --- a/ormar/queryset/clause.py +++ b/ormar/queryset/clause.py @@ -185,7 +185,7 @@ def __init__( self.filter_clauses = filter_clauses[:] self.model_cls = model_cls - self.table = self.model_cls.Meta.table + self.table = self.model_cls.ormar_config.table def prepare_filter( # noqa: A003 self, _own_only: bool = False, **kwargs: Any @@ -203,7 +203,9 @@ def prepare_filter( # noqa: A003 :rtype: Tuple[List[sqlalchemy.sql.elements.TextClause], List[str]] """ if kwargs.get("pk"): - pk_name = self.model_cls.get_column_alias(self.model_cls.Meta.pkname) + pk_name = self.model_cls.get_column_alias( + self.model_cls.ormar_config.pkname + ) kwargs[pk_name] = kwargs.pop("pk") filter_clauses, select_related = self._populate_filter_clauses( @@ -262,7 +264,7 @@ def _register_complex_duplicates(self, select_related: List[str]) -> None: """ prefixes = self._parse_related_prefixes(select_related=select_related) - manager = self.model_cls.Meta.alias_manager + manager = self.model_cls.ormar_config.alias_manager filtered_prefixes = sorted(prefixes, key=lambda x: x.table_prefix) grouped = itertools.groupby(filtered_prefixes, key=lambda x: x.table_prefix) for _, group in grouped: @@ -320,7 +322,7 @@ def _verify_prefix_and_switch(self, action: "FilterAction") -> None: :param action: action to switch prefix in :type action: ormar.queryset.actions.filter_action.FilterAction """ - manager = self.model_cls.Meta.alias_manager + manager = self.model_cls.ormar_config.alias_manager new_alias = manager.resolve_relation_alias(self.model_cls, action.related_str) if "__" in action.related_str and new_alias: action.table_prefix = new_alias diff --git a/ormar/queryset/field_accessor.py b/ormar/queryset/field_accessor.py index b27483771..071f9e7a2 100644 --- a/ormar/queryset/field_accessor.py +++ b/ormar/queryset/field_accessor.py @@ -53,9 +53,10 @@ def __getattr__(self, item: str) -> Any: if ( object.__getattribute__(self, "_model") - and item in object.__getattribute__(self, "_model").Meta.model_fields + and item + in object.__getattribute__(self, "_model").ormar_config.model_fields ): - field = cast("Model", self._model).Meta.model_fields[item] + field = cast("Model", self._model).ormar_config.model_fields[item] if field.is_relation: return FieldAccessor( source_model=self._source_model, diff --git a/ormar/queryset/join.py b/ormar/queryset/join.py index 005eeb2f5..6ef9be05c 100644 --- a/ormar/queryset/join.py +++ b/ormar/queryset/join.py @@ -43,7 +43,9 @@ def __init__( # noqa: CFQ002 self.main_model = main_model self.own_alias = own_alias self.used_aliases = used_aliases - self.target_field = self.main_model.Meta.model_fields[self.relation_name] + self.target_field = self.main_model.ormar_config.model_fields[ + self.relation_name + ] self._next_model: Optional[Type["Model"]] = None self._next_alias: Optional[str] = None @@ -81,7 +83,7 @@ def alias_manager(self) -> AliasManager: :return: alias manager from model's Meta :rtype: AliasManager """ - return self.main_model.Meta.alias_manager + return self.main_model.ormar_config.alias_manager @property def to_table(self) -> sqlalchemy.Table: @@ -90,7 +92,7 @@ def to_table(self) -> sqlalchemy.Table: :return: name of the target table :rtype: str """ - return self.next_model.Meta.table + return self.next_model.ormar_config.table def _on_clause(self, previous_alias: str, from_clause: str, to_clause: str) -> text: """ @@ -108,7 +110,7 @@ def _on_clause(self, previous_alias: str, from_clause: str, to_clause: str) -> t """ left_part = f"{self.next_alias}_{to_clause}" if not previous_alias: - dialect = self.main_model.Meta.database._backend._dialect + dialect = self.main_model.ormar_config.database._backend._dialect table, column = from_clause.split(".") quotter = dialect.identifier_preparer.quote right_part = f"{quotter(table)}.{quotter(column)}" @@ -232,7 +234,9 @@ def _process_m2m_through_table(self) -> None: self.relation_name = new_part self.own_alias = self.next_alias - self.target_field = self.next_model.Meta.model_fields[self.relation_name] + self.target_field = self.next_model.ormar_config.model_fields[ + self.relation_name + ] def _process_m2m_related_name_change(self, reverse: bool = False) -> str: """ @@ -278,7 +282,7 @@ def _process_join(self) -> None: # noqa: CFQ002 on_clause = self._on_clause( previous_alias=self.own_alias, - from_clause=f"{self.target_field.owner.Meta.tablename}.{from_key}", + from_clause=f"{self.target_field.owner.ormar_config.tablename}.{from_key}", to_clause=f"{self.to_table.name}.{to_key}", ) target_table = self.alias_manager.prefixed_table_name( @@ -304,7 +308,7 @@ def _process_join(self) -> None: # noqa: CFQ002 self.used_aliases.append(self.next_alias) def _set_default_primary_key_order_by(self) -> None: - for order_by in self.next_model.Meta.orders_by: + for order_by in self.next_model.ormar_config.orders_by: clause = ormar.OrderAction( order_str=order_by, model_cls=self.next_model, alias=self.next_alias ) @@ -394,16 +398,20 @@ def _get_to_and_from_keys(self) -> Tuple[str, str]: """ if self.target_field.is_multi: to_key = self._process_m2m_related_name_change(reverse=True) - from_key = self.main_model.get_column_alias(self.main_model.Meta.pkname) + from_key = self.main_model.get_column_alias( + self.main_model.ormar_config.pkname + ) elif self.target_field.virtual: to_field = self.target_field.get_related_name() to_key = self.target_field.to.get_column_alias(to_field) - from_key = self.main_model.get_column_alias(self.main_model.Meta.pkname) + from_key = self.main_model.get_column_alias( + self.main_model.ormar_config.pkname + ) else: to_key = self.target_field.to.get_column_alias( - self.target_field.to.Meta.pkname + self.target_field.to.ormar_config.pkname ) from_key = self.main_model.get_column_alias(self.relation_name) diff --git a/ormar/queryset/queries/query.py b/ormar/queryset/queries/query.py index d395f6777..acca91bdb 100644 --- a/ormar/queryset/queries/query.py +++ b/ormar/queryset/queries/query.py @@ -37,7 +37,7 @@ def __init__( # noqa CFQ002 self.excludable = excludable self.model_cls = model_cls - self.table = self.model_cls.Meta.table + self.table = self.model_cls.ormar_config.table self.used_aliases: List[str] = [] @@ -78,7 +78,7 @@ def _apply_default_model_sorting(self) -> None: Applies orders_by from model Meta class (if provided), if it was not provided it was filled by metaclass so it's always there and falls back to pk column """ - for order_by in self.model_cls.Meta.orders_by: + for order_by in self.model_cls.ormar_config.orders_by: clause = ormar.OrderAction(order_str=order_by, model_cls=self.model_cls) self.sorted_orders[clause] = clause.get_text_clause() @@ -113,7 +113,7 @@ def build_select_expression(self) -> Tuple[sqlalchemy.sql.select, List[str]]: self_related_fields = self.model_cls.own_table_columns( model=self.model_cls, excludable=self.excludable, use_alias=True ) - self.columns = self.model_cls.Meta.alias_manager.prefixed_columns( + self.columns = self.model_cls.ormar_config.alias_manager.prefixed_columns( "", self.table, self_related_fields ) self.apply_order_bys_for_primary_model() @@ -179,7 +179,7 @@ def _build_pagination_condition( The condition is added to filters to filter out desired number of main model primary key values. Whole query is used to determine the values. """ - pk_alias = self.model_cls.get_column_alias(self.model_cls.Meta.pkname) + pk_alias = self.model_cls.get_column_alias(self.model_cls.ormar_config.pkname) pk_aliased_name = f"{self.table.name}.{pk_alias}" qry_text = sqlalchemy.text(f"{pk_aliased_name}") maxes = {} diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index ae2f04039..1fd72024c 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -46,7 +46,7 @@ class LegacyRow(dict): # type: ignore if TYPE_CHECKING: # pragma no cover from ormar import Model from ormar.models import T - from ormar.models.metaclass import ModelMeta + from ormar.models.ormar_config import OrmarConfig from ormar.models.excludable import ExcludableItems else: T = TypeVar("T", bound="Model") @@ -84,7 +84,7 @@ def __init__( # noqa CFQ002 self.limit_sql_raw = limit_raw_sql @property - def model_meta(self) -> "ModelMeta": + def model_meta(self) -> "OrmarConfig": """ Shortcut to model class Meta set on QuerySet model. @@ -93,7 +93,7 @@ def model_meta(self) -> "ModelMeta": """ if not self.model_cls: # pragma nocover raise ValueError("Model class of QuerySet is not initialized") - return self.model_cls.Meta + return self.model_cls.ormar_config @property def model(self) -> Type["T"]: @@ -908,7 +908,7 @@ async def first(self, *args: Any, **kwargs: Any) -> "T": order_bys=( [ OrderAction( - order_str=f"{self.model.Meta.pkname}", + order_str=f"{self.model.ormar_config.pkname}", model_cls=self.model_cls, # type: ignore ) ] @@ -970,7 +970,7 @@ async def get(self, *args: Any, **kwargs: Any) -> "T": # noqa: CCR001 order_bys=( [ OrderAction( - order_str=f"-{self.model.Meta.pkname}", + order_str=f"-{self.model.ormar_config.pkname}", model_cls=self.model_cls, # type: ignore ) ] @@ -1226,6 +1226,8 @@ async def bulk_update( # noqa: CCR001 for obj in objects: obj.set_save_status(True) - await cast(Type["Model"], self.model_cls).Meta.signals.post_bulk_update.send( + await cast( + Type["Model"], self.model_cls + ).ormar_config.signals.post_bulk_update.send( sender=self.model_cls, instances=objects # type: ignore ) diff --git a/ormar/queryset/utils.py b/ormar/queryset/utils.py index 4ebe07c7f..d858fd509 100644 --- a/ormar/queryset/utils.py +++ b/ormar/queryset/utils.py @@ -216,7 +216,7 @@ def extract_nested_models( # noqa: CCR001 child = getattr(model, related) if not child: continue - target_model = model_type.Meta.model_fields[related].to + target_model = model_type.ormar_config.model_fields[related].to if isinstance(child, list): extracted.setdefault(target_model.get_name(), []).extend(child) if select_dict[related] is not Ellipsis: @@ -279,9 +279,9 @@ def get_relationship_alias_model_and_str( target_model = source_model previous_model = target_model previous_models = [target_model] - manager = target_model.Meta.alias_manager + manager = target_model.ormar_config.alias_manager for relation in related_parts[:]: - related_field = target_model.Meta.model_fields[relation] + related_field = target_model.ormar_config.model_fields[relation] if related_field.is_through: (previous_model, relation, is_through) = _process_through_field( @@ -331,7 +331,7 @@ def _process_through_field( """ is_through = True related_parts.remove(relation) - through_field = related_field.owner.Meta.model_fields[ + through_field = related_field.owner.ormar_config.model_fields[ related_field.related_name or "" ] if len(previous_models) > 1 and previous_models[-2] == through_field.to: diff --git a/ormar/relations/alias_manager.py b/ormar/relations/alias_manager.py index c8bd1a66c..4cd976a4b 100644 --- a/ormar/relations/alias_manager.py +++ b/ormar/relations/alias_manager.py @@ -134,7 +134,7 @@ def add_relation_type( if parent_key not in self._aliases_new: self.add_alias(parent_key) - to_field = source_model.Meta.model_fields[relation_name] + to_field = source_model.ormar_config.model_fields[relation_name] child_model = to_field.to child_key = f"{child_model.get_name()}_{reverse_name}" if child_key not in self._aliases_new: diff --git a/ormar/relations/querysetproxy.py b/ormar/relations/querysetproxy.py index e27934dbf..c47e37532 100644 --- a/ormar/relations/querysetproxy.py +++ b/ormar/relations/querysetproxy.py @@ -49,11 +49,11 @@ def __init__( self._queryset: Optional["QuerySet[T]"] = qryset self.type_: "RelationType" = type_ self._owner: Union[CallableProxyType, "Model"] = self.relation.manager.owner - self.related_field_name = self._owner.Meta.model_fields[ + self.related_field_name = self._owner.ormar_config.model_fields[ self.relation.field_name ].get_related_name() self.to: Type[T] = to - self.related_field = to.Meta.model_fields[self.related_field_name] + self.related_field = to.ormar_config.model_fields[self.related_field_name] self.owner_pk_value = self._owner.pk self.through_model_name = ( self.related_field.through.get_name() diff --git a/ormar/relations/relation_proxy.py b/ormar/relations/relation_proxy.py index 0169308c7..63e33c041 100644 --- a/ormar/relations/relation_proxy.py +++ b/ormar/relations/relation_proxy.py @@ -71,7 +71,7 @@ def related_field_name(self) -> str: """ if self._related_field_name: return self._related_field_name - owner_field = self._owner.Meta.model_fields[self.field_name] + owner_field = self._owner.ormar_config.model_fields[self.field_name] self._related_field_name = owner_field.get_related_name() return self._related_field_name @@ -245,7 +245,7 @@ def _set_queryset(self) -> "QuerySet[T]": :rtype: QuerySet """ related_field_name = self.related_field_name - pkname = self._owner.get_column_alias(self._owner.Meta.pkname) + pkname = self._owner.get_column_alias(self._owner.ormar_config.pkname) self._check_if_model_saved() kwargs = {f"{related_field_name}__{pkname}": self._owner.pk} queryset = ( diff --git a/poetry.lock b/poetry.lock index b3bb1d8cc..901c40e97 100644 --- a/poetry.lock +++ b/poetry.lock @@ -74,14 +74,14 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} [[package]] name = "anyio" -version = "3.7.0" +version = "3.7.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "anyio-3.7.0-py3-none-any.whl", hash = "sha256:eddca883c4175f14df8aedce21054bfca3adb70ffe76a9f607aef9d7fa2ea7f0"}, - {file = "anyio-3.7.0.tar.gz", hash = "sha256:275d9973793619a5374e1c89a4f4ad3f4b0a5510a2b5b939444bee8f4c4d37ce"}, + {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, + {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, ] [package.dependencies] @@ -91,7 +91,7 @@ sniffio = ">=1.1" typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -doc = ["Sphinx (>=6.1.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme", "sphinxcontrib-jquery"] +doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (<0.22)"] @@ -127,14 +127,14 @@ typed = ["typed-ast"] [[package]] name = "async-timeout" -version = "4.0.2" +version = "4.0.3" description = "Timeout context manager for asyncio programs" category = "main" optional = true -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, - {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, ] [package.dependencies] @@ -305,14 +305,14 @@ files = [ [[package]] name = "certifi" -version = "2023.5.7" +version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, - {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, ] [[package]] @@ -406,99 +406,114 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.1.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "dev" optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, - {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] name = "click" -version = "8.1.3" +version = "8.1.7" description = "Composable command line interface toolkit" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -625,31 +640,35 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "41.0.1" +version = "41.0.7" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699"}, - {file = "cryptography-41.0.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a"}, - {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca"}, - {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43"}, - {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b"}, - {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3"}, - {file = "cryptography-41.0.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db"}, - {file = "cryptography-41.0.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31"}, - {file = "cryptography-41.0.1-cp37-abi3-win32.whl", hash = "sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5"}, - {file = "cryptography-41.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c"}, - {file = "cryptography-41.0.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb"}, - {file = "cryptography-41.0.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3"}, - {file = "cryptography-41.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039"}, - {file = "cryptography-41.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc"}, - {file = "cryptography-41.0.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485"}, - {file = "cryptography-41.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c"}, - {file = "cryptography-41.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a"}, - {file = "cryptography-41.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5"}, - {file = "cryptography-41.0.1.tar.gz", hash = "sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006"}, + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, + {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, + {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, + {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, ] [package.dependencies] @@ -704,26 +723,26 @@ files = [ [[package]] name = "distlib" -version = "0.3.6" +version = "0.3.8" description = "Distribution utilities" category = "dev" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] [[package]] name = "exceptiongroup" -version = "1.1.1" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, - {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -731,22 +750,24 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.100.0b1" +version = "0.103.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.100.0b1-py3-none-any.whl", hash = "sha256:3e45c7209410503e4f372e38d9f47ec01cc1e23bbd4a796f6dfe23023584f622"}, - {file = "fastapi-0.100.0b1.tar.gz", hash = "sha256:2e699a1c924ecbda8b4e942ddd04899038d9bfb39077a1ef7a3164879609dc11"}, + {file = "fastapi-0.103.2-py3-none-any.whl", hash = "sha256:3270de872f0fe9ec809d4bd3d4d890c6d5cc7b9611d721d6438f9dacc8c4ef2e"}, + {file = "fastapi-0.103.2.tar.gz", hash = "sha256:75a11f6bfb8fc4d2bec0bd710c2d5f2829659c0e8c0afd5560fdda6ce25ec653"}, ] [package.dependencies] -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<3.0.0" +anyio = ">=3.7.1,<4.0.0" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" starlette = ">=0.27.0,<0.28.0" +typing-extensions = ">=4.5.0" [package.extras] -all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" @@ -967,14 +988,14 @@ dev = ["flake8", "markdown", "twine", "wheel"] [[package]] name = "gitdb" -version = "4.0.10" +version = "4.0.11" description = "Git Object Database" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, - {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, ] [package.dependencies] @@ -982,104 +1003,105 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.31" +version = "3.1.40" description = "GitPython is a Python library used to interact with Git repositories" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "GitPython-3.1.31-py3-none-any.whl", hash = "sha256:f04893614f6aa713a60cbbe1e6a97403ef633103cdd0ef5eb6efe0deb98dbe8d"}, - {file = "GitPython-3.1.31.tar.gz", hash = "sha256:8ce3bcf69adfdf7c7d503e78fd3b1c492af782d58893b650adb2ac8912ddd573"}, + {file = "GitPython-3.1.40-py3-none-any.whl", hash = "sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a"}, + {file = "GitPython-3.1.40.tar.gz", hash = "sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4"}, ] [package.dependencies] gitdb = ">=4.0.1,<5" typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} +[package.extras] +test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-sugar"] + [[package]] name = "greenlet" -version = "2.0.2" +version = "3.0.2" description = "Lightweight in-process concurrent programming" category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" -files = [ - {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, - {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, - {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, - {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, - {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, - {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, - {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, - {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, - {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, - {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, - {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, - {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, - {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, - {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, - {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, - {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, - {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, - {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, - {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, - {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, - {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, - {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, - {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, - {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, - {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, - {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.0.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9acd8fd67c248b8537953cb3af8787c18a87c33d4dcf6830e410ee1f95a63fd4"}, + {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:339c0272a62fac7e602e4e6ec32a64ff9abadc638b72f17f6713556ed011d493"}, + {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38878744926cec29b5cc3654ef47f3003f14bfbba7230e3c8492393fe29cc28b"}, + {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b3f0497db77cfd034f829678b28267eeeeaf2fc21b3f5041600f7617139e6773"}, + {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1a8a08de7f68506a38f9a2ddb26bbd1480689e66d788fcd4b5f77e2d9ecfcc"}, + {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89a6f6ddcbef4000cda7e205c4c20d319488ff03db961d72d4e73519d2465309"}, + {file = "greenlet-3.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c1f647fe5b94b51488b314c82fdda10a8756d650cee8d3cd29f657c6031bdf73"}, + {file = "greenlet-3.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9560c580c896030ff9c311c603aaf2282234643c90d1dec738a1d93e3e53cd51"}, + {file = "greenlet-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2e9c5423046eec21f6651268cb674dfba97280701e04ef23d312776377313206"}, + {file = "greenlet-3.0.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1fd25dfc5879a82103b3d9e43fa952e3026c221996ff4d32a9c72052544835d"}, + {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cecfdc950dd25f25d6582952e58521bca749cf3eeb7a9bad69237024308c8196"}, + {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edf7a1daba1f7c54326291a8cde58da86ab115b78c91d502be8744f0aa8e3ffa"}, + {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4cf532bf3c58a862196b06947b1b5cc55503884f9b63bf18582a75228d9950e"}, + {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e79fb5a9fb2d0bd3b6573784f5e5adabc0b0566ad3180a028af99523ce8f6138"}, + {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:006c1028ac0cfcc4e772980cfe73f5476041c8c91d15d64f52482fc571149d46"}, + {file = "greenlet-3.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fefd5eb2c0b1adffdf2802ff7df45bfe65988b15f6b972706a0e55d451bffaea"}, + {file = "greenlet-3.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c0fdb8142742ee68e97c106eb81e7d3e883cc739d9c5f2b28bc38a7bafeb6d1"}, + {file = "greenlet-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:8f8d14a0a4e8c670fbce633d8b9a1ee175673a695475acd838e372966845f764"}, + {file = "greenlet-3.0.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:654b84c9527182036747938b81938f1d03fb8321377510bc1854a9370418ab66"}, + {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd5bc4fde0842ff2b9cf33382ad0b4db91c2582db836793d58d174c569637144"}, + {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c27b142a9080bdd5869a2fa7ebf407b3c0b24bd812db925de90e9afe3c417fd6"}, + {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0df7eed98ea23b20e9db64d46eb05671ba33147df9405330695bcd81a73bb0c9"}, + {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb5d60805057d8948065338be6320d35e26b0a72f45db392eb32b70dd6dc9227"}, + {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0e28f5233d64c693382f66d47c362b72089ebf8ac77df7e12ac705c9fa1163d"}, + {file = "greenlet-3.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e4bfa752b3688d74ab1186e2159779ff4867644d2b1ebf16db14281f0445377"}, + {file = "greenlet-3.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c42bb589e6e9f9d8bdd79f02f044dff020d30c1afa6e84c0b56d1ce8a324553c"}, + {file = "greenlet-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:b2cedf279ca38ef3f4ed0d013a6a84a7fc3d9495a716b84a5fc5ff448965f251"}, + {file = "greenlet-3.0.2-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:6d65bec56a7bc352bcf11b275b838df618651109074d455a772d3afe25390b7d"}, + {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0acadbc3f72cb0ee85070e8d36bd2a4673d2abd10731ee73c10222cf2dd4713c"}, + {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14b5d999aefe9ffd2049ad19079f733c3aaa426190ffecadb1d5feacef8fe397"}, + {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f27aa32466993c92d326df982c4acccd9530fe354e938d9e9deada563e71ce76"}, + {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f34a765c5170c0673eb747213a0275ecc749ab3652bdbec324621ed5b2edaef"}, + {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:520fcb53a39ef90f5021c77606952dbbc1da75d77114d69b8d7bded4a8e1a813"}, + {file = "greenlet-3.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1fceb5351ab1601903e714c3028b37f6ea722be6873f46e349a960156c05650"}, + {file = "greenlet-3.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7363756cc439a503505b67983237d1cc19139b66488263eb19f5719a32597836"}, + {file = "greenlet-3.0.2-cp37-cp37m-win32.whl", hash = "sha256:d5547b462b8099b84746461e882a3eb8a6e3f80be46cb6afb8524eeb191d1a30"}, + {file = "greenlet-3.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:950e21562818f9c771989b5b65f990e76f4ac27af66e1bb34634ae67886ede2a"}, + {file = "greenlet-3.0.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d64643317e76b4b41fdba659e7eca29634e5739b8bc394eda3a9127f697ed4b0"}, + {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f9ea7c2c9795549653b6f7569f6bc75d2c7d1f6b2854eb8ce0bc6ec3cb2dd88"}, + {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db4233358d3438369051a2f290f1311a360d25c49f255a6c5d10b5bcb3aa2b49"}, + {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bf77b41798e8417657245b9f3649314218a4a17aefb02bb3992862df32495"}, + {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d0df07a38e41a10dfb62c6fc75ede196572b580f48ee49b9282c65639f3965"}, + {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10d247260db20887ae8857c0cbc750b9170f0b067dd7d38fb68a3f2334393bd3"}, + {file = "greenlet-3.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a37ae53cca36823597fd5f65341b6f7bac2dd69ecd6ca01334bb795460ab150b"}, + {file = "greenlet-3.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:80d068e4b6e2499847d916ef64176811ead6bf210a610859220d537d935ec6fd"}, + {file = "greenlet-3.0.2-cp38-cp38-win32.whl", hash = "sha256:b1405614692ac986490d10d3e1a05e9734f473750d4bee3cf7d1286ef7af7da6"}, + {file = "greenlet-3.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8756a94ed8f293450b0e91119eca2a36332deba69feb2f9ca410d35e74eae1e4"}, + {file = "greenlet-3.0.2-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:2c93cd03acb1499ee4de675e1a4ed8eaaa7227f7949dc55b37182047b006a7aa"}, + {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dac09e3c0b78265d2e6d3cbac2d7c48bd1aa4b04a8ffeda3adde9f1688df2c3"}, + {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ee59c4627c8c4bb3e15949fbcd499abd6b7f4ad9e0bfcb62c65c5e2cabe0ec4"}, + {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18fe39d70d482b22f0014e84947c5aaa7211fb8e13dc4cc1c43ed2aa1db06d9a"}, + {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84bef3cfb6b6bfe258c98c519811c240dbc5b33a523a14933a252e486797c90"}, + {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aecea0442975741e7d69daff9b13c83caff8c13eeb17485afa65f6360a045765"}, + {file = "greenlet-3.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f260e6c2337871a52161824058923df2bbddb38bc11a5cbe71f3474d877c5bd9"}, + {file = "greenlet-3.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fc14dd9554f88c9c1fe04771589ae24db76cd56c8f1104e4381b383d6b71aff8"}, + {file = "greenlet-3.0.2-cp39-cp39-win32.whl", hash = "sha256:bfcecc984d60b20ffe30173b03bfe9ba6cb671b0be1e95c3e2056d4fe7006590"}, + {file = "greenlet-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:c235131bf59d2546bb3ebaa8d436126267392f2e51b85ff45ac60f3a26549af0"}, + {file = "greenlet-3.0.2.tar.gz", hash = "sha256:1c1129bc47266d83444c85a8e990ae22688cf05fb20d7951fd2866007c2ba9bc"}, ] [package.extras] -docs = ["Sphinx", "docutils (<0.18)"] +docs = ["Sphinx"] test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.29.1" +version = "0.30.1" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "griffe-0.29.1-py3-none-any.whl", hash = "sha256:f9edae6b9bb2eb205bebbdd0512a162713b9342ff6e32dc596d95ff64aa71c1f"}, - {file = "griffe-0.29.1.tar.gz", hash = "sha256:460188b719e363019d0d0f4bf2d9f05cf2df24960b42a4138a1524a17b100d9b"}, + {file = "griffe-0.30.1-py3-none-any.whl", hash = "sha256:b2f3df6952995a6bebe19f797189d67aba7c860755d3d21cc80f64d076d0154c"}, + {file = "griffe-0.30.1.tar.gz", hash = "sha256:007cc11acd20becf1bb8f826419a52b9d403bbad9d8c8535699f5440ddc0a109"}, ] [package.dependencies] @@ -1103,14 +1125,14 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "httpcore" -version = "0.17.2" +version = "0.17.3" description = "A minimal low-level HTTP client." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "httpcore-0.17.2-py3-none-any.whl", hash = "sha256:5581b9c12379c4288fe70f43c710d16060c10080617001e6b22a3b6dbcbefd36"}, - {file = "httpcore-0.17.2.tar.gz", hash = "sha256:125f8375ab60036db632f34f4b627a9ad085048eef7cb7d2616fea0f739f98af"}, + {file = "httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"}, + {file = "httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888"}, ] [package.dependencies] @@ -1164,14 +1186,14 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" category = "dev" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] @@ -1227,20 +1249,21 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "markdown" -version = "3.3.7" -description = "Python implementation of Markdown." +version = "3.4.4" +description = "Python implementation of John Gruber's Markdown." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, - {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, + {file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"}, + {file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"}, ] [package.dependencies] importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} [package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"] testing = ["coverage", "pyyaml"] [[package]] @@ -1367,14 +1390,14 @@ files = [ [[package]] name = "mkdocs" -version = "1.4.3" +version = "1.5.3" description = "Project documentation with Markdown." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd"}, - {file = "mkdocs-1.4.3.tar.gz", hash = "sha256:5955093bbd4dd2e9403c5afaf57324ad8b04f16886512a3ee6ef828956481c57"}, + {file = "mkdocs-1.5.3-py3-none-any.whl", hash = "sha256:3b3a78e736b31158d64dbb2f8ba29bd46a379d0c6e324c2246c3bc3d2189cfc1"}, + {file = "mkdocs-1.5.3.tar.gz", hash = "sha256:eb7c99214dcb945313ba30426c2451b735992c73c2e10838f76d09e39ff4d0e2"}, ] [package.dependencies] @@ -1383,9 +1406,12 @@ colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} ghp-import = ">=1.0" importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} jinja2 = ">=2.11.1" -markdown = ">=3.2.1,<3.4" +markdown = ">=3.2.1" +markupsafe = ">=2.0.1" mergedeep = ">=1.3.4" packaging = ">=20.5" +pathspec = ">=0.11.1" +platformdirs = ">=2.2.0" pyyaml = ">=5.1" pyyaml-env-tag = ">=0.1" typing-extensions = {version = ">=3.10", markers = "python_version < \"3.8\""} @@ -1393,7 +1419,7 @@ watchdog = ">=2.0" [package.extras] i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pathspec (==0.11.1)", "platformdirs (==2.2.0)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] [[package]] name = "mkdocs-autorefs" @@ -1428,14 +1454,14 @@ mkdocs = ">=1.0.3" [[package]] name = "mkdocs-literate-nav" -version = "0.6.0" +version = "0.6.1" description = "MkDocs plugin to specify the navigation in Markdown instead of YAML" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs_literate_nav-0.6.0-py3-none-any.whl", hash = "sha256:8c1b84714e5974da5e44e011ec0069275ae7647270c13a679662cf6ffce675a4"}, - {file = "mkdocs_literate_nav-0.6.0.tar.gz", hash = "sha256:81ccbea18163ae8e10bd0bd39237fe70c32a1f2dff6c170779f5d52dd98a0470"}, + {file = "mkdocs_literate_nav-0.6.1-py3-none-any.whl", hash = "sha256:e70bdc4a07050d32da79c0b697bd88e9a104cf3294282e9cb20eec94c6b0f401"}, + {file = "mkdocs_literate_nav-0.6.1.tar.gz", hash = "sha256:78a7ab6d878371728acb0cdc6235c9b0ffc6e83c997b037f4a5c6ff7cef7d759"}, ] [package.dependencies] @@ -1443,21 +1469,21 @@ mkdocs = ">=1.0.3" [[package]] name = "mkdocs-material" -version = "9.1.17" +version = "9.1.21" description = "Documentation that simply works" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs_material-9.1.17-py3-none-any.whl", hash = "sha256:809ed68427fbab0330b0b07bc93175824c3b98f4187060a5c7b46aa8ae398a75"}, - {file = "mkdocs_material-9.1.17.tar.gz", hash = "sha256:5a076524625047bf4ee4da1509ec90626f8fce915839dc07bdae6b59ff4f36f9"}, + {file = "mkdocs_material-9.1.21-py3-none-any.whl", hash = "sha256:58bb2f11ef240632e176d6f0f7d1cff06be1d11c696a5a1b553b808b4280ed47"}, + {file = "mkdocs_material-9.1.21.tar.gz", hash = "sha256:71940cdfca84ab296b6362889c25395b1621273fb16c93deda257adb7ff44ec8"}, ] [package.dependencies] colorama = ">=0.4" jinja2 = ">=3.0" markdown = ">=3.2" -mkdocs = ">=1.4.2" +mkdocs = ">=1.5.0" mkdocs-material-extensions = ">=1.1" pygments = ">=2.14" pymdown-extensions = ">=9.9.1" @@ -1466,30 +1492,30 @@ requests = ">=2.26" [[package]] name = "mkdocs-material-extensions" -version = "1.1.1" +version = "1.2" description = "Extension pack for Python Markdown and MkDocs Material." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs_material_extensions-1.1.1-py3-none-any.whl", hash = "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945"}, - {file = "mkdocs_material_extensions-1.1.1.tar.gz", hash = "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93"}, + {file = "mkdocs_material_extensions-1.2-py3-none-any.whl", hash = "sha256:c767bd6d6305f6420a50f0b541b0c9966d52068839af97029be14443849fb8a1"}, + {file = "mkdocs_material_extensions-1.2.tar.gz", hash = "sha256:27e2d1ed2d031426a6e10d5ea06989d67e90bb02acd588bc5673106b5ee5eedf"}, ] [[package]] name = "mkdocs-section-index" -version = "0.3.5" +version = "0.3.8" description = "MkDocs plugin to allow clickable sections that lead to an index page" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs_section_index-0.3.5-py3-none-any.whl", hash = "sha256:1f6359287b0a823d6297cf1cb6c0a49ed75851d0d1cea8b425b207a45ce10141"}, - {file = "mkdocs_section_index-0.3.5.tar.gz", hash = "sha256:fa8b1ce0649326b1873c6460c1df2bb0c4825fd21e3dd416f13ec212d31edf12"}, + {file = "mkdocs_section_index-0.3.8-py3-none-any.whl", hash = "sha256:823d298d78bc1e73e23678ff60889f3c369c2167b03dba73fea88bd0e268a60d"}, + {file = "mkdocs_section_index-0.3.8.tar.gz", hash = "sha256:bbd209f0da79441baf136ef3a9c40665bb9681d1fb62c73ca2f116fd1388a404"}, ] [package.dependencies] -mkdocs = ">=1.0.3" +mkdocs = ">=1.2" [[package]] name = "mkdocstrings" @@ -1629,14 +1655,14 @@ files = [ [[package]] name = "nest-asyncio" -version = "1.5.6" +version = "1.5.8" description = "Patch asyncio to allow nested event loops" category = "dev" optional = false python-versions = ">=3.5" files = [ - {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"}, - {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, + {file = "nest_asyncio-1.5.8-py3-none-any.whl", hash = "sha256:accda7a339a70599cb08f9dd09a67e0c2ef8d8d6f4c07f96ab203f2ae254e48d"}, + {file = "nest_asyncio-1.5.8.tar.gz", hash = "sha256:25aa2ca0d2a5b5531956b9e273b45cf664cae2b145101d73b86b199978d48fdb"}, ] [[package]] @@ -1656,114 +1682,128 @@ setuptools = "*" [[package]] name = "orjson" -version = "3.9.1" +version = "3.9.7" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "orjson-3.9.1-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4434b7b786fdc394b95d029fb99949d7c2b05bbd4bf5cb5e3906be96ffeee3b"}, - {file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09faf14f74ed47e773fa56833be118e04aa534956f661eb491522970b7478e3b"}, - {file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:503eb86a8d53a187fe66aa80c69295a3ca35475804da89a9547e4fce5f803822"}, - {file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20f2804b5a1dbd3609c086041bd243519224d47716efd7429db6c03ed28b7cc3"}, - {file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fd828e0656615a711c4cc4da70f3cac142e66a6703ba876c20156a14e28e3fa"}, - {file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec53d648176f873203b9c700a0abacab33ca1ab595066e9d616f98cdc56f4434"}, - {file = "orjson-3.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e186ae76b0d97c505500664193ddf508c13c1e675d9b25f1f4414a7606100da6"}, - {file = "orjson-3.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d4edee78503016f4df30aeede0d999b3cb11fb56f47e9db0e487bce0aaca9285"}, - {file = "orjson-3.9.1-cp310-none-win_amd64.whl", hash = "sha256:a4cc5d21e68af982d9a2528ac61e604f092c60eed27aef3324969c68f182ec7e"}, - {file = "orjson-3.9.1-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:761b6efd33c49de20dd73ce64cc59da62c0dab10aa6015f582680e0663cc792c"}, - {file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31229f9d0b8dc2ef7ee7e4393f2e4433a28e16582d4b25afbfccc9d68dc768f8"}, - {file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b7ab18d55ecb1de543d452f0a5f8094b52282b916aa4097ac11a4c79f317b86"}, - {file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db774344c39041f4801c7dfe03483df9203cbd6c84e601a65908e5552228dd25"}, - {file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae47ef8c0fe89c4677db7e9e1fb2093ca6e66c3acbee5442d84d74e727edad5e"}, - {file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:103952c21575b9805803c98add2eaecd005580a1e746292ed2ec0d76dd3b9746"}, - {file = "orjson-3.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2cb0121e6f2c9da3eddf049b99b95fef0adf8480ea7cb544ce858706cdf916eb"}, - {file = "orjson-3.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:24d4ddaa2876e657c0fd32902b5c451fd2afc35159d66a58da7837357044b8c2"}, - {file = "orjson-3.9.1-cp311-none-win_amd64.whl", hash = "sha256:0b53b5f72cf536dd8aa4fc4c95e7e09a7adb119f8ff8ee6cc60f735d7740ad6a"}, - {file = "orjson-3.9.1-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4b68d01a506242316a07f1d2f29fb0a8b36cee30a7c35076f1ef59dce0890c1"}, - {file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9dd4abe6c6fd352f00f4246d85228f6a9847d0cc14f4d54ee553718c225388f"}, - {file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e20bca5e13041e31ceba7a09bf142e6d63c8a7467f5a9c974f8c13377c75af2"}, - {file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8ae0467d01eb1e4bcffef4486d964bfd1c2e608103e75f7074ed34be5df48cc"}, - {file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06f6ab4697fab090517f295915318763a97a12ee8186054adf21c1e6f6abbd3d"}, - {file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8515867713301fa065c58ec4c9053ba1a22c35113ab4acad555317b8fd802e50"}, - {file = "orjson-3.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:393d0697d1dfa18d27d193e980c04fdfb672c87f7765b87952f550521e21b627"}, - {file = "orjson-3.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d96747662d3666f79119e5d28c124e7d356c7dc195cd4b09faea4031c9079dc9"}, - {file = "orjson-3.9.1-cp37-none-win_amd64.whl", hash = "sha256:6d173d3921dd58a068c88ec22baea7dbc87a137411501618b1292a9d6252318e"}, - {file = "orjson-3.9.1-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d1c2b0b4246c992ce2529fc610a446b945f1429445ece1c1f826a234c829a918"}, - {file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19f70ba1f441e1c4bb1a581f0baa092e8b3e3ce5b2aac2e1e090f0ac097966da"}, - {file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:375d65f002e686212aac42680aed044872c45ee4bc656cf63d4a215137a6124a"}, - {file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4751cee4a7b1daeacb90a7f5adf2170ccab893c3ab7c5cea58b45a13f89b30b3"}, - {file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d9a2a4b2302d5ebc3695498ebc305c3568e5ad4f3501eb30a6405a32d8af22"}, - {file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46b4facc32643b2689dfc292c0c463985dac4b6ab504799cf51fc3c6959ed668"}, - {file = "orjson-3.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec7c8a0f1bf35da0d5fd14f8956f3b82a9a6918a3c6963d718dfd414d6d3b604"}, - {file = "orjson-3.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d3a40b0fbe06ccd4d6a99e523d20b47985655bcada8d1eba485b1b32a43e4904"}, - {file = "orjson-3.9.1-cp38-none-win_amd64.whl", hash = "sha256:402f9d3edfec4560a98880224ec10eba4c5f7b4791e4bc0d4f4d8df5faf2a006"}, - {file = "orjson-3.9.1-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:49c0d78dcd34626e2e934f1192d7c052b94e0ecadc5f386fd2bda6d2e03dadf5"}, - {file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:125f63e56d38393daa0a1a6dc6fedefca16c538614b66ea5997c3bd3af35ef26"}, - {file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08927970365d2e1f3ce4894f9ff928a7b865d53f26768f1bbdd85dd4fee3e966"}, - {file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9a744e212d4780ecd67f4b6b128b2e727bee1df03e7059cddb2dfe1083e7dc4"}, - {file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d1dbf36db7240c61eec98c8d21545d671bce70be0730deb2c0d772e06b71af3"}, - {file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a1e384626f76b66df615f7bb622a79a25c166d08c5d2151ffd41f24c4cc104"}, - {file = "orjson-3.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:15d28872fb055bf17ffca913826e618af61b2f689d2b170f72ecae1a86f80d52"}, - {file = "orjson-3.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e4d905338f9ef32c67566929dfbfbb23cc80287af8a2c38930fb0eda3d40b76"}, - {file = "orjson-3.9.1-cp39-none-win_amd64.whl", hash = "sha256:48a27da6c7306965846565cc385611d03382bbd84120008653aa2f6741e2105d"}, - {file = "orjson-3.9.1.tar.gz", hash = "sha256:db373a25ec4a4fccf8186f9a72a1b3442837e40807a736a815ab42481e83b7d0"}, + {file = "orjson-3.9.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6df858e37c321cefbf27fe7ece30a950bcc3a75618a804a0dcef7ed9dd9c92d"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5198633137780d78b86bb54dafaaa9baea698b4f059456cd4554ab7009619221"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e736815b30f7e3c9044ec06a98ee59e217a833227e10eb157f44071faddd7c5"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a19e4074bc98793458b4b3ba35a9a1d132179345e60e152a1bb48c538ab863c4"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80acafe396ab689a326ab0d80f8cc61dec0dd2c5dca5b4b3825e7b1e0132c101"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:355efdbbf0cecc3bd9b12589b8f8e9f03c813a115efa53f8dc2a523bfdb01334"}, + {file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3aab72d2cef7f1dd6104c89b0b4d6b416b0db5ca87cc2fac5f79c5601f549cc2"}, + {file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36b1df2e4095368ee388190687cb1b8557c67bc38400a942a1a77713580b50ae"}, + {file = "orjson-3.9.7-cp310-none-win32.whl", hash = "sha256:e94b7b31aa0d65f5b7c72dd8f8227dbd3e30354b99e7a9af096d967a77f2a580"}, + {file = "orjson-3.9.7-cp310-none-win_amd64.whl", hash = "sha256:82720ab0cf5bb436bbd97a319ac529aee06077ff7e61cab57cee04a596c4f9b4"}, + {file = "orjson-3.9.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1f8b47650f90e298b78ecf4df003f66f54acdba6a0f763cc4df1eab048fe3738"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f738fee63eb263530efd4d2e9c76316c1f47b3bbf38c1bf45ae9625feed0395e"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38e34c3a21ed41a7dbd5349e24c3725be5416641fdeedf8f56fcbab6d981c900"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21a3344163be3b2c7e22cef14fa5abe957a892b2ea0525ee86ad8186921b6cf0"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23be6b22aab83f440b62a6f5975bcabeecb672bc627face6a83bc7aeb495dc7e"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5205ec0dfab1887dd383597012199f5175035e782cdb013c542187d280ca443"}, + {file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8769806ea0b45d7bf75cad253fba9ac6700b7050ebb19337ff6b4e9060f963fa"}, + {file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f9e01239abea2f52a429fe9d95c96df95f078f0172489d691b4a848ace54a476"}, + {file = "orjson-3.9.7-cp311-none-win32.whl", hash = "sha256:8bdb6c911dae5fbf110fe4f5cba578437526334df381b3554b6ab7f626e5eeca"}, + {file = "orjson-3.9.7-cp311-none-win_amd64.whl", hash = "sha256:9d62c583b5110e6a5cf5169ab616aa4ec71f2c0c30f833306f9e378cf51b6c86"}, + {file = "orjson-3.9.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1c3cee5c23979deb8d1b82dc4cc49be59cccc0547999dbe9adb434bb7af11cf7"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a347d7b43cb609e780ff8d7b3107d4bcb5b6fd09c2702aa7bdf52f15ed09fa09"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:154fd67216c2ca38a2edb4089584504fbb6c0694b518b9020ad35ecc97252bb9"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ea3e63e61b4b0beeb08508458bdff2daca7a321468d3c4b320a758a2f554d31"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb0b0b2476f357eb2975ff040ef23978137aa674cd86204cfd15d2d17318588"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b9a20a03576c6b7022926f614ac5a6b0914486825eac89196adf3267c6489d"}, + {file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:915e22c93e7b7b636240c5a79da5f6e4e84988d699656c8e27f2ac4c95b8dcc0"}, + {file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f26fb3e8e3e2ee405c947ff44a3e384e8fa1843bc35830fe6f3d9a95a1147b6e"}, + {file = "orjson-3.9.7-cp312-none-win_amd64.whl", hash = "sha256:d8692948cada6ee21f33db5e23460f71c8010d6dfcfe293c9b96737600a7df78"}, + {file = "orjson-3.9.7-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7bab596678d29ad969a524823c4e828929a90c09e91cc438e0ad79b37ce41166"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63ef3d371ea0b7239ace284cab9cd00d9c92b73119a7c274b437adb09bda35e6"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f8fcf696bbbc584c0c7ed4adb92fd2ad7d153a50258842787bc1524e50d7081"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90fe73a1f0321265126cbba13677dcceb367d926c7a65807bd80916af4c17047"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45a47f41b6c3beeb31ac5cf0ff7524987cfcce0a10c43156eb3ee8d92d92bf22"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a2937f528c84e64be20cb80e70cea76a6dfb74b628a04dab130679d4454395c"}, + {file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b4fb306c96e04c5863d52ba8d65137917a3d999059c11e659eba7b75a69167bd"}, + {file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:410aa9d34ad1089898f3db461b7b744d0efcf9252a9415bbdf23540d4f67589f"}, + {file = "orjson-3.9.7-cp37-none-win32.whl", hash = "sha256:26ffb398de58247ff7bde895fe30817a036f967b0ad0e1cf2b54bda5f8dcfdd9"}, + {file = "orjson-3.9.7-cp37-none-win_amd64.whl", hash = "sha256:bcb9a60ed2101af2af450318cd89c6b8313e9f8df4e8fb12b657b2e97227cf08"}, + {file = "orjson-3.9.7-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5da9032dac184b2ae2da4bce423edff7db34bfd936ebd7d4207ea45840f03905"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7951af8f2998045c656ba8062e8edf5e83fd82b912534ab1de1345de08a41d2b"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8e59650292aa3a8ea78073fc84184538783966528e442a1b9ed653aa282edcf"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9274ba499e7dfb8a651ee876d80386b481336d3868cba29af839370514e4dce0"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca1706e8b8b565e934c142db6a9592e6401dc430e4b067a97781a997070c5378"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cc275cf6dcb1a248e1876cdefd3f9b5f01063854acdfd687ec360cd3c9712a"}, + {file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:11c10f31f2c2056585f89d8229a56013bc2fe5de51e095ebc71868d070a8dd81"}, + {file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cf334ce1d2fadd1bf3e5e9bf15e58e0c42b26eb6590875ce65bd877d917a58aa"}, + {file = "orjson-3.9.7-cp38-none-win32.whl", hash = "sha256:76a0fc023910d8a8ab64daed8d31d608446d2d77c6474b616b34537aa7b79c7f"}, + {file = "orjson-3.9.7-cp38-none-win_amd64.whl", hash = "sha256:7a34a199d89d82d1897fd4a47820eb50947eec9cda5fd73f4578ff692a912f89"}, + {file = "orjson-3.9.7-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e7e7f44e091b93eb39db88bb0cb765db09b7a7f64aea2f35e7d86cbf47046c65"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01d647b2a9c45a23a84c3e70e19d120011cba5f56131d185c1b78685457320bb"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0eb850a87e900a9c484150c414e21af53a6125a13f6e378cf4cc11ae86c8f9c5"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f4b0042d8388ac85b8330b65406c84c3229420a05068445c13ca28cc222f1f7"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd3e7aae977c723cc1dbb82f97babdb5e5fbce109630fbabb2ea5053523c89d3"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c616b796358a70b1f675a24628e4823b67d9e376df2703e893da58247458956"}, + {file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3ba725cf5cf87d2d2d988d39c6a2a8b6fc983d78ff71bc728b0be54c869c884"}, + {file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4891d4c934f88b6c29b56395dfc7014ebf7e10b9e22ffd9877784e16c6b2064f"}, + {file = "orjson-3.9.7-cp39-none-win32.whl", hash = "sha256:14d3fb6cd1040a4a4a530b28e8085131ed94ebc90d72793c59a713de34b60838"}, + {file = "orjson-3.9.7-cp39-none-win_amd64.whl", hash = "sha256:9ef82157bbcecd75d6296d5d8b2d792242afcd064eb1ac573f8847b52e58f677"}, + {file = "orjson-3.9.7.tar.gz", hash = "sha256:85e39198f78e2f7e054d296395f6c96f5e02892337746ef5b6a1bf3ed5910142"}, ] [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] name = "pathspec" -version = "0.11.1" +version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, - {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, ] [[package]] name = "pbr" -version = "5.11.1" +version = "6.0.0" description = "Python Build Reasonableness" category = "dev" optional = false python-versions = ">=2.6" files = [ - {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"}, - {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"}, + {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"}, + {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"}, ] [[package]] name = "platformdirs" -version = "3.8.0" +version = "4.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.8.0-py3-none-any.whl", hash = "sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"}, - {file = "platformdirs-3.8.0.tar.gz", hash = "sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc"}, + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, ] [package.dependencies] -typing-extensions = {version = ">=4.6.3", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" @@ -1806,74 +1846,84 @@ virtualenv = ">=20.10.0" [[package]] name = "psycopg2-binary" -version = "2.9.6" +version = "2.9.9" description = "psycopg2 - Python-PostgreSQL Database Adapter" category = "main" optional = true -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "psycopg2-binary-2.9.6.tar.gz", hash = "sha256:1f64dcfb8f6e0c014c7f55e51c9759f024f70ea572fbdef123f85318c297947c"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d26e0342183c762de3276cca7a530d574d4e25121ca7d6e4a98e4f05cb8e4df7"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c48d8f2db17f27d41fb0e2ecd703ea41984ee19362cbce52c097963b3a1b4365"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe9dc0a884a8848075e576c1de0290d85a533a9f6e9c4e564f19adf8f6e54a7"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a76e027f87753f9bd1ab5f7c9cb8c7628d1077ef927f5e2446477153a602f2c"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6460c7a99fc939b849431f1e73e013d54aa54293f30f1109019c56a0b2b2ec2f"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae102a98c547ee2288637af07393dd33f440c25e5cd79556b04e3fca13325e5f"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9972aad21f965599ed0106f65334230ce826e5ae69fda7cbd688d24fa922415e"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7a40c00dbe17c0af5bdd55aafd6ff6679f94a9be9513a4c7e071baf3d7d22a70"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:cacbdc5839bdff804dfebc058fe25684cae322987f7a38b0168bc1b2df703fb1"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f0438fa20fb6c7e202863e0d5ab02c246d35efb1d164e052f2f3bfe2b152bd0"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-win32.whl", hash = "sha256:b6c8288bb8a84b47e07013bb4850f50538aa913d487579e1921724631d02ea1b"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-win_amd64.whl", hash = "sha256:61b047a0537bbc3afae10f134dc6393823882eb263088c271331602b672e52e9"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:964b4dfb7c1c1965ac4c1978b0f755cc4bd698e8aa2b7667c575fb5f04ebe06b"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afe64e9b8ea66866a771996f6ff14447e8082ea26e675a295ad3bdbffdd72afb"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15e2ee79e7cf29582ef770de7dab3d286431b01c3bb598f8e05e09601b890081"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfa74c903a3c1f0d9b1c7e7b53ed2d929a4910e272add6700c38f365a6002820"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b83456c2d4979e08ff56180a76429263ea254c3f6552cd14ada95cff1dec9bb8"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0645376d399bfd64da57148694d78e1f431b1e1ee1054872a5713125681cf1be"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e99e34c82309dd78959ba3c1590975b5d3c862d6f279f843d47d26ff89d7d7e1"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4ea29fc3ad9d91162c52b578f211ff1c931d8a38e1f58e684c45aa470adf19e2"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4ac30da8b4f57187dbf449294d23b808f8f53cad6b1fc3623fa8a6c11d176dd0"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e78e6e2a00c223e164c417628572a90093c031ed724492c763721c2e0bc2a8df"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-win32.whl", hash = "sha256:1876843d8e31c89c399e31b97d4b9725a3575bb9c2af92038464231ec40f9edb"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-win_amd64.whl", hash = "sha256:b4b24f75d16a89cc6b4cdff0eb6a910a966ecd476d1e73f7ce5985ff1328e9a6"}, - {file = "psycopg2_binary-2.9.6-cp36-cp36m-win32.whl", hash = "sha256:498807b927ca2510baea1b05cc91d7da4718a0f53cb766c154c417a39f1820a0"}, - {file = "psycopg2_binary-2.9.6-cp36-cp36m-win_amd64.whl", hash = "sha256:0d236c2825fa656a2d98bbb0e52370a2e852e5a0ec45fc4f402977313329174d"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:34b9ccdf210cbbb1303c7c4db2905fa0319391bd5904d32689e6dd5c963d2ea8"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d2222e61f313c4848ff05353653bf5f5cf6ce34df540e4274516880d9c3763"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30637a20623e2a2eacc420059be11527f4458ef54352d870b8181a4c3020ae6b"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8122cfc7cae0da9a3077216528b8bb3629c43b25053284cc868744bfe71eb141"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38601cbbfe600362c43714482f43b7c110b20cb0f8172422c616b09b85a750c5"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c7e62ab8b332147a7593a385d4f368874d5fe4ad4e341770d4983442d89603e3"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2ab652e729ff4ad76d400df2624d223d6e265ef81bb8aa17fbd63607878ecbee"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:c83a74b68270028dc8ee74d38ecfaf9c90eed23c8959fca95bd703d25b82c88e"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d4e6036decf4b72d6425d5b29bbd3e8f0ff1059cda7ac7b96d6ac5ed34ffbacd"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-win32.whl", hash = "sha256:a8c28fd40a4226b4a84bdf2d2b5b37d2c7bd49486b5adcc200e8c7ec991dfa7e"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-win_amd64.whl", hash = "sha256:51537e3d299be0db9137b321dfb6a5022caaab275775680e0c3d281feefaca6b"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cf4499e0a83b7b7edcb8dabecbd8501d0d3a5ef66457200f77bde3d210d5debb"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7e13a5a2c01151f1208d5207e42f33ba86d561b7a89fca67c700b9486a06d0e2"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e0f754d27fddcfd74006455b6e04e6705d6c31a612ec69ddc040a5468e44b4e"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d57c3fd55d9058645d26ae37d76e61156a27722097229d32a9e73ed54819982a"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71f14375d6f73b62800530b581aed3ada394039877818b2d5f7fc77e3bb6894d"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:441cc2f8869a4f0f4bb408475e5ae0ee1f3b55b33f350406150277f7f35384fc"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:65bee1e49fa6f9cf327ce0e01c4c10f39165ee76d35c846ade7cb0ec6683e303"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:af335bac6b666cc6aea16f11d486c3b794029d9df029967f9938a4bed59b6a19"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:cfec476887aa231b8548ece2e06d28edc87c1397ebd83922299af2e051cf2827"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:65c07febd1936d63bfde78948b76cd4c2a411572a44ac50719ead41947d0f26b"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-win32.whl", hash = "sha256:4dfb4be774c4436a4526d0c554af0cc2e02082c38303852a36f6456ece7b3503"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-win_amd64.whl", hash = "sha256:02c6e3cf3439e213e4ee930308dc122d6fb4d4bea9aef4a12535fbd605d1a2fe"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e9182eb20f41417ea1dd8e8f7888c4d7c6e805f8a7c98c1081778a3da2bee3e4"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8a6979cf527e2603d349a91060f428bcb135aea2be3201dff794813256c274f1"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8338a271cb71d8da40b023a35d9c1e919eba6cbd8fa20a54b748a332c355d896"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ed340d2b858d6e6fb5083f87c09996506af483227735de6964a6100b4e6a54"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f81e65376e52f03422e1fb475c9514185669943798ed019ac50410fb4c4df232"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfb13af3c5dd3a9588000910178de17010ebcccd37b4f9794b00595e3a8ddad3"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4c727b597c6444a16e9119386b59388f8a424223302d0c06c676ec8b4bc1f963"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4d67fbdaf177da06374473ef6f7ed8cc0a9dc640b01abfe9e8a2ccb1b1402c1f"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0892ef645c2fabb0c75ec32d79f4252542d0caec1d5d949630e7d242ca4681a3"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:02c0f3757a4300cf379eb49f543fb7ac527fb00144d39246ee40e1df684ab514"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-win32.whl", hash = "sha256:c3dba7dab16709a33a847e5cd756767271697041fbe3fe97c215b1fc1f5c9848"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-win_amd64.whl", hash = "sha256:f6a88f384335bb27812293fdb11ac6aee2ca3f51d3c7820fe03de0a304ab6249"}, + {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, ] [[package]] @@ -1914,19 +1964,20 @@ files = [ [[package]] name = "pydantic" -version = "2.0b3" +version = "2.5.2" description = "Data validation using Python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-2.0b3-py3-none-any.whl", hash = "sha256:dd6a8f835aceef1a399329478c355c91985f582afda7027055834d6822aa0ce2"}, - {file = "pydantic-2.0b3.tar.gz", hash = "sha256:057fb3050b8d3952153a0df45188882096ac53fe087b196fd0d877442b0c029b"}, + {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, + {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "0.39.0" +importlib-metadata = {version = "*", markers = "python_version == \"3.7\""} +pydantic-core = "2.14.5" typing-extensions = ">=4.6.1" [package.extras] @@ -1934,97 +1985,121 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "0.39.0" +version = "2.14.5" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic_core-0.39.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:361135e456636aecad3c15ceabc206fe93b4f86778ca24eefd707952954b7e70"}, - {file = "pydantic_core-0.39.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c9c16fc80e2612b0121eb425890e2e29f03e3038bbd53e5b637cd72aad2c5339"}, - {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73f785920e974f86d2e37a7fc44a5fdd3e9b6d40fba94137da7a1e02c4dd7c11"}, - {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9e18e91b5f4172ea5ebc8fe0461acf6f2de73d4b85b47aee26924dcd304141a"}, - {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_24_armv7l.whl", hash = "sha256:ac8756c26cbfc57e89ff52817a2802e97376948de002ffe39adb238fbb12c8db"}, - {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:8ac4ba34ac3977fa5c6cef5921564133e1295b9d202fed2d6e62187f61651f3c"}, - {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_24_s390x.whl", hash = "sha256:f8992a135442959269d2c013bd9913c837d5ea215b0e480cda1820c7310df55b"}, - {file = "pydantic_core-0.39.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3cb0cdc1c5c036aa7caccf6a28e9a2ce3058ae18aceb143870a6a379235b075d"}, - {file = "pydantic_core-0.39.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:30ad66243a64818e8afb584596cc9f7f8738406ffe1b4ab0be00e23375753b7c"}, - {file = "pydantic_core-0.39.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e86833a13a4f00f264d04f3f36048ce3fea0a92a730db6c9c9c0bf33e277bc2"}, - {file = "pydantic_core-0.39.0-cp310-none-win32.whl", hash = "sha256:dc12b16753591143bdd0c117d74fbe46fda84b4a8eb0383931811819d8679c89"}, - {file = "pydantic_core-0.39.0-cp310-none-win_amd64.whl", hash = "sha256:ddf0177f2324200cf9ea3100d4232be275c8986a4cb9b1892e1f53d2584f6b17"}, - {file = "pydantic_core-0.39.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:9f1ddc997865f29eee3fea397885595d361a76df80356fec8c47f45b987b7490"}, - {file = "pydantic_core-0.39.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7ad056aeb02a474957fa950ff169549e214cec5f0b5c18dae683b0d21227def"}, - {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8178dc88a246c60fb8264a8422587abc209cac1d9160329af8a6f5f89797cb3"}, - {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:126db921ac7c72cb5d8d1b46540d594d559c25e243b3515aed040a0cd0eafac8"}, - {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:d3a8d0734b1e82df4a725fa39a1b78625c407b8cf31ae1652382a2f4c8c757b4"}, - {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:87e4d828c0cc28e8ec1abad2e83110e0cca175b3799fc3eeab22e615cefc551f"}, - {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:472049006abb4070750d530c96d76122497aec86b99c618d583e596fe986ad0a"}, - {file = "pydantic_core-0.39.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9595444868ece2e67b5e64a583eab10756491d9bf4e6d3876410299297d4adb3"}, - {file = "pydantic_core-0.39.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:00c3a5ab18f355a0b082019fdc4af41b61c4a2e33d97af44c69b611d818bdfe2"}, - {file = "pydantic_core-0.39.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7bf7470f621285303a5aa6b3e4fb148c5b69f8ee485a920ee9cc1472fd282d2e"}, - {file = "pydantic_core-0.39.0-cp311-none-win32.whl", hash = "sha256:3696a567b7517c09ed7dae942fa5b38cd552af5160d0905b76e9607b87e31d01"}, - {file = "pydantic_core-0.39.0-cp311-none-win_amd64.whl", hash = "sha256:c9b4909e971e8745af251cecd92aa55f9239bbc9a9630811dd53a00a2b5285f8"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9aba06c25f356c0fb11f1dd2d0317a5599f223a3b283ebbc1aa3a1100a6920f7"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:bd5f3e98d112c6eab8c41cf2baf3dab8006c3223d5f2c9695b1cba7ab87bbfb5"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351a34da43f44a52bbd52380322bfb364f2efe423275c4917c8c26100c1b8ced"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ac25daeb3ea45ecd4e8580f7375e6434daf02c6ca185f246f2e682de554ab5"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_24_armv7l.whl", hash = "sha256:45926ab2adef2deff4fc89e12bf5ba015ad297efefcd0f84b8689123a6c3b126"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:549a0940b7164b23d52df4d6bd73637e989688d28dbeb9e24d87a27da48f23bc"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_24_s390x.whl", hash = "sha256:a0f7d1454f86865cd2ec47e36ebe2e20cca5be71eaa5c2e422adf1e0355ae705"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8849794ae4da5d244d215ee582e83e169120c475a7e05f1adf227035b9edbde3"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e9f98a9df2cea76b1a8bd70d00b4ee3b7597887281c2e85c8ad690ed881ef34"}, - {file = "pydantic_core-0.39.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1f89064cf78b57bf2930a14b41aa4b4240bd2993a57efb56b5ad8be02f4048b3"}, - {file = "pydantic_core-0.39.0-cp37-none-win32.whl", hash = "sha256:2bfe35d886d93c7911b4d56ab3a6725a7866b35f09aceaf3d0d64babed701b73"}, - {file = "pydantic_core-0.39.0-cp37-none-win_amd64.whl", hash = "sha256:84675545b74ce4ea53f0e2413f182db1501b1684d6359f7c2cb4d37d24a9afec"}, - {file = "pydantic_core-0.39.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:abbcbc69868ad7f642caa319a7b5f829e6f9b6db5194b6b82b7a9561ac992663"}, - {file = "pydantic_core-0.39.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a5ca573f261ea525c5bb10e03d41dd9ce76aea93b75f9ca2dc5dc4ef147ea2a3"}, - {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1f187d852ca78b9e23a0155be5f759f65f5e5c7dc4b29b7ea7aa5df48537ba1"}, - {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4060e765690727095969f7038e8e1c7251d4bd518e151174b5cb54dae0163c68"}, - {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_24_armv7l.whl", hash = "sha256:b749a22e311e235974516a4bca00afdf4f2e67dd7773d3850c1b17f1da1131b1"}, - {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:749c0a2038ca7fb3a29ff7f9ce7d3248d8bb9f42d2ef609b4e4c158e74368145"}, - {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_24_s390x.whl", hash = "sha256:e77a053384a29c4ffdad2a717809e347b864c582c407ab88eb9ff3fa3bce22a7"}, - {file = "pydantic_core-0.39.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef212fafe222ae7fdf38ba16b5c7bb7eddf1b44cc901bc3056569eefcf54da94"}, - {file = "pydantic_core-0.39.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9602b61c85d9c12b0e66792eebc85152b565c24431a69c47f3cba811b1507389"}, - {file = "pydantic_core-0.39.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5ccb4a21713a831f888c0bf22be4888df475650f699cc35a675cb91cc55e780b"}, - {file = "pydantic_core-0.39.0-cp38-none-win32.whl", hash = "sha256:3a5795a0521ce88adbffd16796e85cdd06546805ff869fed0cac1a9c297d9445"}, - {file = "pydantic_core-0.39.0-cp38-none-win_amd64.whl", hash = "sha256:dc8234bd4325341eb660a86dba3688a5287789309a84261b3dbe76d4dd0472e8"}, - {file = "pydantic_core-0.39.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:c2fb59f98fd0f9f3ee1b77b2c44f282ed8b1cc52d332c2d2a34b6364f63dbfa1"}, - {file = "pydantic_core-0.39.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:103179d734dafb5da5f74065d1a18274709684a9dc01c61f119c5e39dea4d2df"}, - {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3b42892739cd3e27c2efbab6682fa91ec07c76381db1ca66da2d889c21e1c8a"}, - {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0203bc58c551d018bff3ce3bc863cd2c88504dbb96f79357fdaa22955db64ffe"}, - {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_24_armv7l.whl", hash = "sha256:bb4cea3c63defa0fe891af206ad04c8b167852feb6bfba7c1cc4f26a4a2eb39e"}, - {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:17a08e9af181097759362182bffa5614cd8c1278f12bab529e6e3bdc4b2d3860"}, - {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_24_s390x.whl", hash = "sha256:5438ffb320ad430de40de405078b0770beb1eec00e54de18a63c842d114d86b9"}, - {file = "pydantic_core-0.39.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf55dc04bb037c06d256e22254401b10fbc3a478835837987435e3c77ec929f9"}, - {file = "pydantic_core-0.39.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c7b5e09e5e6c7cf2ed0ccb5a1ddf1f6d12131315ff70d100fc197711df4a37e"}, - {file = "pydantic_core-0.39.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0ef384f3b4aa5ef4c66d47f4446ca9dc8adbfbc7bf74d1b31b19cc2e2bdf9e8"}, - {file = "pydantic_core-0.39.0-cp39-none-win32.whl", hash = "sha256:579c69e5a7bf2fd3dedd3c51e91b1beb0c89782ea6c0d1ffd8e48259b70f9d61"}, - {file = "pydantic_core-0.39.0-cp39-none-win_amd64.whl", hash = "sha256:3a4d4d87dc988d9c52d4e7e31b77d6036b4cab36109826b57cd293ae3179440d"}, - {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d3240340147504a1d6a3c86f43b644469f8c61992e0d88287701ee8f6b1b0b2d"}, - {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d32b45650e5bb8670b73d0f9acdae184197308f5a5ecf8e714849c76fd0a6ed"}, - {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ee34d942a3ab3d55db4945b42ce000c5ca2fd749ab9bbc3fb4ddab41742cbbd"}, - {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5570c884284a5e69278c4bb259c1694d64a5d9bc9a28674d088134246ad73358"}, - {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a5a377d9bf58a99e55d74167c658cb1f170cc1c008b849f5a8ec31b7b0eb65e7"}, - {file = "pydantic_core-0.39.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:45f55076c3844ccf1a9f912d5bef61282baae203b30a7b0158add0b4a2141036"}, - {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:e7d2a139d384911ee97ad2e9472ae4e79e9fedf278fa8c31b3e391c0279c0207"}, - {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f29f3197b1b50550c299ad8700918fbe383412df6f864fe02190a958b60a3c29"}, - {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71e12169625eb4b6939617333dd1aa671c156a44c44880db207c47a2e4c9fe81"}, - {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:058ea15957753eeb0547bbcb9aca1dca1f11969f0517a6f988d708110c4717e4"}, - {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:711d3a4c9ed8cce84dd55284ff9f4494b825930154a52a37cd02ac4e3a5fd62d"}, - {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5cf2849e22925411a15d955c03197f71c6507fcdfcaeee110a7202f6e436b5fa"}, - {file = "pydantic_core-0.39.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cf6cff67dcf885f36e9f8a8771225df6b9cd76f308d0c7af66bfd2776f471c7c"}, - {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:96100fb53a7384a99c6121ea90f01aa1cb6100af8dd25f227a5132f38b9199df"}, - {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bed383476707e6aeb8d9d6fc83a9b9a6b4f0a00ae440ca3f1cc17686ae3e45ab"}, - {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4908e1bbafa91dcbcc8778bfe11ede713ef18dafac4a7f66b7108d348d46e5ea"}, - {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2c52a9269c302b75265e45f72e1c3a3d4e473c90f11d3c5671ddfa7ba891eae"}, - {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:99de1fe8dcb3dc6e853ff6b96da4faa54384bbc4e73dbeb7dc8473f7e9d84243"}, - {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b2352ef56d0a5157dea6d39f3342980523673ac7f08967e39a68e06c168b94a4"}, - {file = "pydantic_core-0.39.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7cdcd13b84411d6194de988044b21c2859fcc7c673e0f6dd92e854489c21ae2f"}, - {file = "pydantic_core-0.39.0.tar.gz", hash = "sha256:8368d0510d0020d1bbb4124b31fb663e17e5661b5cc85c48e2b9d9bb0a378d9f"}, -] - -[package.dependencies] -typing_extensions = {version = "*", markers = "python_version < \"3.11.0\""} + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, + {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, + {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, + {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, + {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, + {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, + {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, + {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, + {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, + {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, + {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, + {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, + {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, + {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, + {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, + {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pyflakes" @@ -2040,35 +2115,39 @@ files = [ [[package]] name = "pygments" -version = "2.15.1" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, - {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.0.1" +version = "10.2.1" description = "Extension pack for Python Markdown." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pymdown_extensions-10.0.1-py3-none-any.whl", hash = "sha256:ae66d84013c5d027ce055693e09a4628b67e9dec5bce05727e45b0918e36f274"}, - {file = "pymdown_extensions-10.0.1.tar.gz", hash = "sha256:b44e1093a43b8a975eae17b03c3a77aad4681b3b56fce60ce746dbef1944c8cb"}, + {file = "pymdown_extensions-10.2.1-py3-none-any.whl", hash = "sha256:bded105eb8d93f88f2f821f00108cb70cef1269db6a40128c09c5f48bfc60ea4"}, + {file = "pymdown_extensions-10.2.1.tar.gz", hash = "sha256:d0c534b4a5725a4be7ccef25d65a4c97dba58b54ad7c813babf0eb5ba9c81591"}, ] [package.dependencies] markdown = ">=3.2" pyyaml = "*" +[package.extras] +extra = ["pygments (>=2.12)"] + [[package]] name = "pymysql" version = "1.1.0" @@ -2087,14 +2166,14 @@ rsa = ["cryptography"] [[package]] name = "pytest" -version = "7.4.0" +version = "7.4.3" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, ] [package.dependencies] @@ -2111,14 +2190,14 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.21.0" +version = "0.21.1" description = "Pytest support for asyncio" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, - {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, + {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, + {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, ] [package.dependencies] @@ -2186,52 +2265,52 @@ six = ">=1.5" [[package]] name = "pyyaml" -version = "6.0" +version = "6.0.1" description = "YAML parser and emitter for Python" category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] [[package]] @@ -2251,100 +2330,100 @@ pyyaml = "*" [[package]] name = "regex" -version = "2023.6.3" +version = "2023.10.3" description = "Alternative regular expression module, to replace re." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "regex-2023.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:824bf3ac11001849aec3fa1d69abcb67aac3e150a933963fb12bda5151fe1bfd"}, - {file = "regex-2023.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:05ed27acdf4465c95826962528f9e8d41dbf9b1aa8531a387dee6ed215a3e9ef"}, - {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b49c764f88a79160fa64f9a7b425620e87c9f46095ef9c9920542ab2495c8bc"}, - {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e3f1316c2293e5469f8f09dc2d76efb6c3982d3da91ba95061a7e69489a14ef"}, - {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43e1dd9d12df9004246bacb79a0e5886b3b6071b32e41f83b0acbf293f820ee8"}, - {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4959e8bcbfda5146477d21c3a8ad81b185cd252f3d0d6e4724a5ef11c012fb06"}, - {file = "regex-2023.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af4dd387354dc83a3bff67127a124c21116feb0d2ef536805c454721c5d7993d"}, - {file = "regex-2023.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2239d95d8e243658b8dbb36b12bd10c33ad6e6933a54d36ff053713f129aa536"}, - {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:890e5a11c97cf0d0c550eb661b937a1e45431ffa79803b942a057c4fb12a2da2"}, - {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a8105e9af3b029f243ab11ad47c19b566482c150c754e4c717900a798806b222"}, - {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:25be746a8ec7bc7b082783216de8e9473803706723b3f6bef34b3d0ed03d57e2"}, - {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:3676f1dd082be28b1266c93f618ee07741b704ab7b68501a173ce7d8d0d0ca18"}, - {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:10cb847aeb1728412c666ab2e2000ba6f174f25b2bdc7292e7dd71b16db07568"}, - {file = "regex-2023.6.3-cp310-cp310-win32.whl", hash = "sha256:dbbbfce33cd98f97f6bffb17801b0576e653f4fdb1d399b2ea89638bc8d08ae1"}, - {file = "regex-2023.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:c5f8037000eb21e4823aa485149f2299eb589f8d1fe4b448036d230c3f4e68e0"}, - {file = "regex-2023.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c123f662be8ec5ab4ea72ea300359023a5d1df095b7ead76fedcd8babbedf969"}, - {file = "regex-2023.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9edcbad1f8a407e450fbac88d89e04e0b99a08473f666a3f3de0fd292badb6aa"}, - {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcba6dae7de533c876255317c11f3abe4907ba7d9aa15d13e3d9710d4315ec0e"}, - {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29cdd471ebf9e0f2fb3cac165efedc3c58db841d83a518b082077e612d3ee5df"}, - {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12b74fbbf6cbbf9dbce20eb9b5879469e97aeeaa874145517563cca4029db65c"}, - {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c29ca1bd61b16b67be247be87390ef1d1ef702800f91fbd1991f5c4421ebae8"}, - {file = "regex-2023.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77f09bc4b55d4bf7cc5eba785d87001d6757b7c9eec237fe2af57aba1a071d9"}, - {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ea353ecb6ab5f7e7d2f4372b1e779796ebd7b37352d290096978fea83c4dba0c"}, - {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:10590510780b7541969287512d1b43f19f965c2ece6c9b1c00fc367b29d8dce7"}, - {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e2fbd6236aae3b7f9d514312cdb58e6494ee1c76a9948adde6eba33eb1c4264f"}, - {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:6b2675068c8b56f6bfd5a2bda55b8accbb96c02fd563704732fd1c95e2083461"}, - {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74419d2b50ecb98360cfaa2974da8689cb3b45b9deff0dcf489c0d333bcc1477"}, - {file = "regex-2023.6.3-cp311-cp311-win32.whl", hash = "sha256:fb5ec16523dc573a4b277663a2b5a364e2099902d3944c9419a40ebd56a118f9"}, - {file = "regex-2023.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:09e4a1a6acc39294a36b7338819b10baceb227f7f7dbbea0506d419b5a1dd8af"}, - {file = "regex-2023.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0654bca0cdf28a5956c83839162692725159f4cda8d63e0911a2c0dc76166525"}, - {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:463b6a3ceb5ca952e66550a4532cef94c9a0c80dc156c4cc343041951aec1697"}, - {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87b2a5bb5e78ee0ad1de71c664d6eb536dc3947a46a69182a90f4410f5e3f7dd"}, - {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6343c6928282c1f6a9db41f5fd551662310e8774c0e5ebccb767002fcf663ca9"}, - {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6192d5af2ccd2a38877bfef086d35e6659566a335b1492786ff254c168b1693"}, - {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74390d18c75054947e4194019077e243c06fbb62e541d8817a0fa822ea310c14"}, - {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:742e19a90d9bb2f4a6cf2862b8b06dea5e09b96c9f2df1779e53432d7275331f"}, - {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8abbc5d54ea0ee80e37fef009e3cec5dafd722ed3c829126253d3e22f3846f1e"}, - {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c2b867c17a7a7ae44c43ebbeb1b5ff406b3e8d5b3e14662683e5e66e6cc868d3"}, - {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d831c2f8ff278179705ca59f7e8524069c1a989e716a1874d6d1aab6119d91d1"}, - {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ee2d1a9a253b1729bb2de27d41f696ae893507c7db224436abe83ee25356f5c1"}, - {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:61474f0b41fe1a80e8dfa70f70ea1e047387b7cd01c85ec88fa44f5d7561d787"}, - {file = "regex-2023.6.3-cp36-cp36m-win32.whl", hash = "sha256:0b71e63226e393b534105fcbdd8740410dc6b0854c2bfa39bbda6b0d40e59a54"}, - {file = "regex-2023.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bbb02fd4462f37060122e5acacec78e49c0fbb303c30dd49c7f493cf21fc5b27"}, - {file = "regex-2023.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b862c2b9d5ae38a68b92e215b93f98d4c5e9454fa36aae4450f61dd33ff48487"}, - {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:976d7a304b59ede34ca2921305b57356694f9e6879db323fd90a80f865d355a3"}, - {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:83320a09188e0e6c39088355d423aa9d056ad57a0b6c6381b300ec1a04ec3d16"}, - {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9427a399501818a7564f8c90eced1e9e20709ece36be701f394ada99890ea4b3"}, - {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178bbc1b2ec40eaca599d13c092079bf529679bf0371c602edaa555e10b41c3"}, - {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:837328d14cde912af625d5f303ec29f7e28cdab588674897baafaf505341f2fc"}, - {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d44dc13229905ae96dd2ae2dd7cebf824ee92bc52e8cf03dcead37d926da019"}, - {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d54af539295392611e7efbe94e827311eb8b29668e2b3f4cadcfe6f46df9c777"}, - {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7117d10690c38a622e54c432dfbbd3cbd92f09401d622902c32f6d377e2300ee"}, - {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bb60b503ec8a6e4e3e03a681072fa3a5adcbfa5479fa2d898ae2b4a8e24c4591"}, - {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:65ba8603753cec91c71de423a943ba506363b0e5c3fdb913ef8f9caa14b2c7e0"}, - {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:271f0bdba3c70b58e6f500b205d10a36fb4b58bd06ac61381b68de66442efddb"}, - {file = "regex-2023.6.3-cp37-cp37m-win32.whl", hash = "sha256:9beb322958aaca059f34975b0df135181f2e5d7a13b84d3e0e45434749cb20f7"}, - {file = "regex-2023.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fea75c3710d4f31389eed3c02f62d0b66a9da282521075061ce875eb5300cf23"}, - {file = "regex-2023.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f56fcb7ff7bf7404becdfc60b1e81a6d0561807051fd2f1860b0d0348156a07"}, - {file = "regex-2023.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d2da3abc88711bce7557412310dfa50327d5769a31d1c894b58eb256459dc289"}, - {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a99b50300df5add73d307cf66abea093304a07eb017bce94f01e795090dea87c"}, - {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5708089ed5b40a7b2dc561e0c8baa9535b77771b64a8330b684823cfd5116036"}, - {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:687ea9d78a4b1cf82f8479cab23678aff723108df3edeac098e5b2498879f4a7"}, - {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3850beab9f527f06ccc94b446c864059c57651b3f911fddb8d9d3ec1d1b25d"}, - {file = "regex-2023.6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8915cc96abeb8983cea1df3c939e3c6e1ac778340c17732eb63bb96247b91d2"}, - {file = "regex-2023.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:841d6e0e5663d4c7b4c8099c9997be748677d46cbf43f9f471150e560791f7ff"}, - {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9edce5281f965cf135e19840f4d93d55b3835122aa76ccacfd389e880ba4cf82"}, - {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b956231ebdc45f5b7a2e1f90f66a12be9610ce775fe1b1d50414aac1e9206c06"}, - {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:36efeba71c6539d23c4643be88295ce8c82c88bbd7c65e8a24081d2ca123da3f"}, - {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:cf67ca618b4fd34aee78740bea954d7c69fdda419eb208c2c0c7060bb822d747"}, - {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b4598b1897837067a57b08147a68ac026c1e73b31ef6e36deeeb1fa60b2933c9"}, - {file = "regex-2023.6.3-cp38-cp38-win32.whl", hash = "sha256:f415f802fbcafed5dcc694c13b1292f07fe0befdb94aa8a52905bd115ff41e88"}, - {file = "regex-2023.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:d4f03bb71d482f979bda92e1427f3ec9b220e62a7dd337af0aa6b47bf4498f72"}, - {file = "regex-2023.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccf91346b7bd20c790310c4147eee6ed495a54ddb6737162a36ce9dbef3e4751"}, - {file = "regex-2023.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b28f5024a3a041009eb4c333863d7894d191215b39576535c6734cd88b0fcb68"}, - {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0bb18053dfcfed432cc3ac632b5e5e5c5b7e55fb3f8090e867bfd9b054dbcbf"}, - {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5bfb3004f2144a084a16ce19ca56b8ac46e6fd0651f54269fc9e230edb5e4a"}, - {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c6b48d0fa50d8f4df3daf451be7f9689c2bde1a52b1225c5926e3f54b6a9ed1"}, - {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:051da80e6eeb6e239e394ae60704d2b566aa6a7aed6f2890a7967307267a5dc6"}, - {file = "regex-2023.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4c3b7fa4cdaa69268748665a1a6ff70c014d39bb69c50fda64b396c9116cf77"}, - {file = "regex-2023.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:457b6cce21bee41ac292d6753d5e94dcbc5c9e3e3a834da285b0bde7aa4a11e9"}, - {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aad51907d74fc183033ad796dd4c2e080d1adcc4fd3c0fd4fd499f30c03011cd"}, - {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0385e73da22363778ef2324950e08b689abdf0b108a7d8decb403ad7f5191938"}, - {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c6a57b742133830eec44d9b2290daf5cbe0a2f1d6acee1b3c7b1c7b2f3606df7"}, - {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3e5219bf9e75993d73ab3d25985c857c77e614525fac9ae02b1bebd92f7cecac"}, - {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e5087a3c59eef624a4591ef9eaa6e9a8d8a94c779dade95d27c0bc24650261cd"}, - {file = "regex-2023.6.3-cp39-cp39-win32.whl", hash = "sha256:20326216cc2afe69b6e98528160b225d72f85ab080cbdf0b11528cbbaba2248f"}, - {file = "regex-2023.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:bdff5eab10e59cf26bc479f565e25ed71a7d041d1ded04ccf9aee1d9f208487a"}, - {file = "regex-2023.6.3.tar.gz", hash = "sha256:72d1a25bf36d2050ceb35b517afe13864865268dfb45910e2e17a84be6cbfeb0"}, + {file = "regex-2023.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4c34d4f73ea738223a094d8e0ffd6d2c1a1b4c175da34d6b0de3d8d69bee6bcc"}, + {file = "regex-2023.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8f4e49fc3ce020f65411432183e6775f24e02dff617281094ba6ab079ef0915"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cd1bccf99d3ef1ab6ba835308ad85be040e6a11b0977ef7ea8c8005f01a3c29"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81dce2ddc9f6e8f543d94b05d56e70d03a0774d32f6cca53e978dc01e4fc75b8"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c6b4d23c04831e3ab61717a707a5d763b300213db49ca680edf8bf13ab5d91b"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c15ad0aee158a15e17e0495e1e18741573d04eb6da06d8b84af726cfc1ed02ee"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6239d4e2e0b52c8bd38c51b760cd870069f0bdf99700a62cd509d7a031749a55"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4a8bf76e3182797c6b1afa5b822d1d5802ff30284abe4599e1247be4fd6b03be"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9c727bbcf0065cbb20f39d2b4f932f8fa1631c3e01fcedc979bd4f51fe051c5"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3ccf2716add72f80714b9a63899b67fa711b654be3fcdd34fa391d2d274ce767"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:107ac60d1bfdc3edb53be75e2a52aff7481b92817cfdddd9b4519ccf0e54a6ff"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:00ba3c9818e33f1fa974693fb55d24cdc8ebafcb2e4207680669d8f8d7cca79a"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f0a47efb1dbef13af9c9a54a94a0b814902e547b7f21acb29434504d18f36e3a"}, + {file = "regex-2023.10.3-cp310-cp310-win32.whl", hash = "sha256:36362386b813fa6c9146da6149a001b7bd063dabc4d49522a1f7aa65b725c7ec"}, + {file = "regex-2023.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:c65a3b5330b54103e7d21cac3f6bf3900d46f6d50138d73343d9e5b2900b2353"}, + {file = "regex-2023.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90a79bce019c442604662d17bf69df99090e24cdc6ad95b18b6725c2988a490e"}, + {file = "regex-2023.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c7964c2183c3e6cce3f497e3a9f49d182e969f2dc3aeeadfa18945ff7bdd7051"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ef80829117a8061f974b2fda8ec799717242353bff55f8a29411794d635d964"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5addc9d0209a9afca5fc070f93b726bf7003bd63a427f65ef797a931782e7edc"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c148bec483cc4b421562b4bcedb8e28a3b84fcc8f0aa4418e10898f3c2c0eb9b"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d1f21af4c1539051049796a0f50aa342f9a27cde57318f2fc41ed50b0dbc4ac"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b9ac09853b2a3e0d0082104036579809679e7715671cfbf89d83c1cb2a30f58"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ebedc192abbc7fd13c5ee800e83a6df252bec691eb2c4bedc9f8b2e2903f5e2a"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d8a993c0a0ffd5f2d3bda23d0cd75e7086736f8f8268de8a82fbc4bd0ac6791e"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:be6b7b8d42d3090b6c80793524fa66c57ad7ee3fe9722b258aec6d0672543fd0"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4023e2efc35a30e66e938de5aef42b520c20e7eda7bb5fb12c35e5d09a4c43f6"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d47840dc05e0ba04fe2e26f15126de7c755496d5a8aae4a08bda4dd8d646c54"}, + {file = "regex-2023.10.3-cp311-cp311-win32.whl", hash = "sha256:9145f092b5d1977ec8c0ab46e7b3381b2fd069957b9862a43bd383e5c01d18c2"}, + {file = "regex-2023.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:b6104f9a46bd8743e4f738afef69b153c4b8b592d35ae46db07fc28ae3d5fb7c"}, + {file = "regex-2023.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff507ae210371d4b1fe316d03433ac099f184d570a1a611e541923f78f05037"}, + {file = "regex-2023.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be5e22bbb67924dea15039c3282fa4cc6cdfbe0cbbd1c0515f9223186fc2ec5f"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a992f702c9be9c72fa46f01ca6e18d131906a7180950958f766c2aa294d4b41"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7434a61b158be563c1362d9071358f8ab91b8d928728cd2882af060481244c9e"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2169b2dcabf4e608416f7f9468737583ce5f0a6e8677c4efbf795ce81109d7c"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9e908ef5889cda4de038892b9accc36d33d72fb3e12c747e2799a0e806ec841"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12bd4bc2c632742c7ce20db48e0d99afdc05e03f0b4c1af90542e05b809a03d9"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bc72c231f5449d86d6c7d9cc7cd819b6eb30134bb770b8cfdc0765e48ef9c420"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bce8814b076f0ce5766dc87d5a056b0e9437b8e0cd351b9a6c4e1134a7dfbda9"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:ba7cd6dc4d585ea544c1412019921570ebd8a597fabf475acc4528210d7c4a6f"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b0c7d2f698e83f15228ba41c135501cfe7d5740181d5903e250e47f617eb4292"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5a8f91c64f390ecee09ff793319f30a0f32492e99f5dc1c72bc361f23ccd0a9a"}, + {file = "regex-2023.10.3-cp312-cp312-win32.whl", hash = "sha256:ad08a69728ff3c79866d729b095872afe1e0557251da4abb2c5faff15a91d19a"}, + {file = "regex-2023.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:39cdf8d141d6d44e8d5a12a8569d5a227f645c87df4f92179bd06e2e2705e76b"}, + {file = "regex-2023.10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4a3ee019a9befe84fa3e917a2dd378807e423d013377a884c1970a3c2792d293"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76066d7ff61ba6bf3cb5efe2428fc82aac91802844c022d849a1f0f53820502d"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe50b61bab1b1ec260fa7cd91106fa9fece57e6beba05630afe27c71259c59b"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fd88f373cb71e6b59b7fa597e47e518282455c2734fd4306a05ca219a1991b0"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ab05a182c7937fb374f7e946f04fb23a0c0699c0450e9fb02ef567412d2fa3"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dac37cf08fcf2094159922edc7a2784cfcc5c70f8354469f79ed085f0328ebdf"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e54ddd0bb8fb626aa1f9ba7b36629564544954fff9669b15da3610c22b9a0991"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3367007ad1951fde612bf65b0dffc8fd681a4ab98ac86957d16491400d661302"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:16f8740eb6dbacc7113e3097b0a36065a02e37b47c936b551805d40340fb9971"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f4f2ca6df64cbdd27f27b34f35adb640b5d2d77264228554e68deda54456eb11"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:39807cbcbe406efca2a233884e169d056c35aa7e9f343d4e78665246a332f597"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7eece6fbd3eae4a92d7c748ae825cbc1ee41a89bb1c3db05b5578ed3cfcfd7cb"}, + {file = "regex-2023.10.3-cp37-cp37m-win32.whl", hash = "sha256:ce615c92d90df8373d9e13acddd154152645c0dc060871abf6bd43809673d20a"}, + {file = "regex-2023.10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f649fa32fe734c4abdfd4edbb8381c74abf5f34bc0b3271ce687b23729299ed"}, + {file = "regex-2023.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b98b7681a9437262947f41c7fac567c7e1f6eddd94b0483596d320092004533"}, + {file = "regex-2023.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:91dc1d531f80c862441d7b66c4505cd6ea9d312f01fb2f4654f40c6fdf5cc37a"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82fcc1f1cc3ff1ab8a57ba619b149b907072e750815c5ba63e7aa2e1163384a4"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7979b834ec7a33aafae34a90aad9f914c41fd6eaa8474e66953f3f6f7cbd4368"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef71561f82a89af6cfcbee47f0fabfdb6e63788a9258e913955d89fdd96902ab"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd829712de97753367153ed84f2de752b86cd1f7a88b55a3a775eb52eafe8a94"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00e871d83a45eee2f8688d7e6849609c2ca2a04a6d48fba3dff4deef35d14f07"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:706e7b739fdd17cb89e1fbf712d9dc21311fc2333f6d435eac2d4ee81985098c"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cc3f1c053b73f20c7ad88b0d1d23be7e7b3901229ce89f5000a8399746a6e039"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f85739e80d13644b981a88f529d79c5bdf646b460ba190bffcaf6d57b2a9863"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:741ba2f511cc9626b7561a440f87d658aabb3d6b744a86a3c025f866b4d19e7f"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e77c90ab5997e85901da85131fd36acd0ed2221368199b65f0d11bca44549711"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:979c24cbefaf2420c4e377ecd1f165ea08cc3d1fbb44bdc51bccbbf7c66a2cb4"}, + {file = "regex-2023.10.3-cp38-cp38-win32.whl", hash = "sha256:58837f9d221744d4c92d2cf7201c6acd19623b50c643b56992cbd2b745485d3d"}, + {file = "regex-2023.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:c55853684fe08d4897c37dfc5faeff70607a5f1806c8be148f1695be4a63414b"}, + {file = "regex-2023.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2c54e23836650bdf2c18222c87f6f840d4943944146ca479858404fedeb9f9af"}, + {file = "regex-2023.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:69c0771ca5653c7d4b65203cbfc5e66db9375f1078689459fe196fe08b7b4930"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ac965a998e1388e6ff2e9781f499ad1eaa41e962a40d11c7823c9952c77123e"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c0e8fae5b27caa34177bdfa5a960c46ff2f78ee2d45c6db15ae3f64ecadde14"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c56c3d47da04f921b73ff9415fbaa939f684d47293f071aa9cbb13c94afc17d"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ef1e014eed78ab650bef9a6a9cbe50b052c0aebe553fb2881e0453717573f52"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d29338556a59423d9ff7b6eb0cb89ead2b0875e08fe522f3e068b955c3e7b59b"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9c6d0ced3c06d0f183b73d3c5920727268d2201aa0fe6d55c60d68c792ff3588"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:994645a46c6a740ee8ce8df7911d4aee458d9b1bc5639bc968226763d07f00fa"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:66e2fe786ef28da2b28e222c89502b2af984858091675044d93cb50e6f46d7af"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:11175910f62b2b8c055f2b089e0fedd694fe2be3941b3e2633653bc51064c528"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:06e9abc0e4c9ab4779c74ad99c3fc10d3967d03114449acc2c2762ad4472b8ca"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fb02e4257376ae25c6dd95a5aec377f9b18c09be6ebdefa7ad209b9137b73d48"}, + {file = "regex-2023.10.3-cp39-cp39-win32.whl", hash = "sha256:3b2c3502603fab52d7619b882c25a6850b766ebd1b18de3df23b2f939360e1bd"}, + {file = "regex-2023.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:adbccd17dcaff65704c856bd29951c58a1bd4b2b0f8ad6b826dbd543fe740988"}, + {file = "regex-2023.10.3.tar.gz", hash = "sha256:3fef4f844d2290ee0ba57addcec17eec9e3df73f10a2748485dfd6a3a188cc0f"}, ] [[package]] @@ -2371,14 +2450,14 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" -version = "13.4.2" +version = "13.7.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" category = "dev" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.4.2-py3-none-any.whl", hash = "sha256:8f87bc7ee54675732fa66a05ebfe489e27264caeeff3728c945d25971b6485ec"}, - {file = "rich-13.4.2.tar.gz", hash = "sha256:d653d6bccede5844304c605d5aac802c7cf9621efd700b46c7ec2b51ea914898"}, + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, ] [package.dependencies] @@ -2420,14 +2499,14 @@ files = [ [[package]] name = "smmap" -version = "5.0.0" +version = "5.0.1" description = "A pure Python implementation of a sliding window memory map manager" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, - {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, ] [[package]] @@ -2539,14 +2618,14 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam [[package]] name = "stdlib-list" -version = "0.9.0" -description = "A list of Python Standard Libraries (2.7 through 3.9)." +version = "0.10.0" +description = "A list of Python Standard Libraries (2.7 through 3.12)." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "stdlib_list-0.9.0-py3-none-any.whl", hash = "sha256:f79957d59e41930d44afcd81e465f740b9a7a9828707a40e24ab1092b12bd423"}, - {file = "stdlib_list-0.9.0.tar.gz", hash = "sha256:98eb66135976c96b4ee3f4c0ef0552ebb5a9977ce3028433db79f4738b02af26"}, + {file = "stdlib_list-0.10.0-py3-none-any.whl", hash = "sha256:b3a911bc441d03e0332dd1a9e7d0870ba3bb0a542a74d7524f54fb431256e214"}, + {file = "stdlib_list-0.10.0.tar.gz", hash = "sha256:6519c50d645513ed287657bfe856d527f277331540691ddeaf77b25459964a14"}, ] [package.extras] @@ -2586,48 +2665,65 @@ files = [ [[package]] name = "typed-ast" -version = "1.5.4" +version = "1.5.5" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, + {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, + {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, + {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, + {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, + {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, + {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, + {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, + {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, + {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, + {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, + {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, ] [[package]] name = "types-aiofiles" -version = "23.1.0.4" +version = "23.2.0.0" description = "Typing stubs for aiofiles" category = "dev" optional = false python-versions = "*" files = [ - {file = "types-aiofiles-23.1.0.4.tar.gz", hash = "sha256:89a58cd0ae93b37a22c323c22d250bd65dde6833f6c6f3c1824784e56f47109f"}, - {file = "types_aiofiles-23.1.0.4-py3-none-any.whl", hash = "sha256:65a862f0d36e6b8e1b2df601ba7aeeb2eba8e2f9764ba9d0989bdd498ed8c857"}, + {file = "types-aiofiles-23.2.0.0.tar.gz", hash = "sha256:b6a7127bd232e0802532837b84140b1cd5df19ee60bea3a5699720d2b583361b"}, + {file = "types_aiofiles-23.2.0.0-py3-none-any.whl", hash = "sha256:5d6719e8148cb2a9c4ea46dad86d50d3b675c46a940adca698533a8d2216d53d"}, ] [[package]] @@ -2692,89 +2788,77 @@ files = [ [[package]] name = "types-pymysql" -version = "1.0.19.7" +version = "1.1.0.1" description = "Typing stubs for PyMySQL" category = "dev" optional = false python-versions = "*" files = [ - {file = "types-PyMySQL-1.0.19.7.tar.gz", hash = "sha256:8ea7083a3bd37c4e77f38d8d93e488fba3bb03e3d3d41cc52cd92110375ed517"}, - {file = "types_PyMySQL-1.0.19.7-py3-none-any.whl", hash = "sha256:672f0e3e5070da2dc58448d289b878c5c99febb37c9f2cbe309779301ae914fb"}, + {file = "types-PyMySQL-1.1.0.1.tar.gz", hash = "sha256:72bdaecb88de4a30bc3e1842e1d4522ceb3c4b2e883a6a2a7a7162775dd27b93"}, + {file = "types_PyMySQL-1.1.0.1-py3-none-any.whl", hash = "sha256:9aec9ee0453314d477ef26e5832b4a992bc4cc3557358d62b0fe4af760a7728f"}, ] [[package]] name = "types-requests" -version = "2.31.0.1" +version = "2.31.0.10" description = "Typing stubs for requests" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "types-requests-2.31.0.1.tar.gz", hash = "sha256:3de667cffa123ce698591de0ad7db034a5317457a596eb0b4944e5a9d9e8d1ac"}, - {file = "types_requests-2.31.0.1-py3-none-any.whl", hash = "sha256:afb06ef8f25ba83d59a1d424bd7a5a939082f94b94e90ab5e6116bd2559deaa3"}, + {file = "types-requests-2.31.0.10.tar.gz", hash = "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92"}, + {file = "types_requests-2.31.0.10-py3-none-any.whl", hash = "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc"}, ] [package.dependencies] -types-urllib3 = "*" +urllib3 = ">=2" [[package]] name = "types-toml" -version = "0.10.8.6" +version = "0.10.8.7" description = "Typing stubs for toml" category = "dev" optional = false python-versions = "*" files = [ - {file = "types-toml-0.10.8.6.tar.gz", hash = "sha256:6d3ac79e36c9ee593c5d4fb33a50cca0e3adceb6ef5cff8b8e5aef67b4c4aaf2"}, - {file = "types_toml-0.10.8.6-py3-none-any.whl", hash = "sha256:de7b2bb1831d6f7a4b554671ffe5875e729753496961b3e9b202745e4955dafa"}, + {file = "types-toml-0.10.8.7.tar.gz", hash = "sha256:58b0781c681e671ff0b5c0319309910689f4ab40e8a2431e205d70c94bb6efb1"}, + {file = "types_toml-0.10.8.7-py3-none-any.whl", hash = "sha256:61951da6ad410794c97bec035d59376ce1cbf4453dc9b6f90477e81e4442d631"}, ] [[package]] name = "types-ujson" -version = "5.8.0.0" +version = "5.9.0.0" description = "Typing stubs for ujson" category = "dev" optional = false -python-versions = "*" -files = [ - {file = "types-ujson-5.8.0.0.tar.gz", hash = "sha256:2856a8d0883475bec80c1ac772c006ea691215cc55ded21647b5c87c86249cbb"}, - {file = "types_ujson-5.8.0.0-py3-none-any.whl", hash = "sha256:481c27a7bc758fc94de330dcd885ba2fbf5879dd3dfd1c7b6b46f5b98d41ca85"}, -] - -[[package]] -name = "types-urllib3" -version = "1.26.25.13" -description = "Typing stubs for urllib3" -category = "dev" -optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "types-urllib3-1.26.25.13.tar.gz", hash = "sha256:3300538c9dc11dad32eae4827ac313f5d986b8b21494801f1bf97a1ac6c03ae5"}, - {file = "types_urllib3-1.26.25.13-py3-none-any.whl", hash = "sha256:5dbd1d2bef14efee43f5318b5d36d805a489f6600252bb53626d4bfafd95e27c"}, + {file = "types-ujson-5.9.0.0.tar.gz", hash = "sha256:7e7042454dc7cd7f31b09c420d7caf36b93d30bdf4b8db93791bd0561713d017"}, + {file = "types_ujson-5.9.0.0-py3-none-any.whl", hash = "sha256:f274fa604ed6317effcd1c424ef4cf292c3b0689cb118fb3180689d40ed1f4ed"}, ] [[package]] name = "typing-extensions" -version = "4.6.3" +version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, - {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] [[package]] name = "urllib3" -version = "2.0.3" +version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "urllib3-2.0.3-py3-none-any.whl", hash = "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"}, - {file = "urllib3-2.0.3.tar.gz", hash = "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"}, + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, ] [package.extras] @@ -2785,25 +2869,25 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.23.1" +version = "20.25.0" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.23.1-py3-none-any.whl", hash = "sha256:34da10f14fea9be20e0fd7f04aba9732f84e593dac291b757ce42e3368a39419"}, - {file = "virtualenv-20.23.1.tar.gz", hash = "sha256:8ff19a38c1021c742148edc4f81cb43d7f8c6816d2ede2ab72af5b84c749ade1"}, + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, ] [package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.12,<4" +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""} -platformdirs = ">=3.5.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "watchdog" @@ -2847,55 +2931,62 @@ watchmedo = ["PyYAML (>=3.10)"] [[package]] name = "yappi" -version = "1.4.0" +version = "1.6.0" description = "Yet Another Python Profiler" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "yappi-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:71a6bce588d03240d8c05aa734d97d69c595ac382644701eaaca2421f6e37c9e"}, - {file = "yappi-1.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d80262ef4bf8ebd7c81e37832b41fe3b0b74621a24eb853b0444e06b01a44a1a"}, - {file = "yappi-1.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8791dbdf17673fb14a6cff150a8b2c85a5e40c455eebb37a62ea4dc74c077408"}, - {file = "yappi-1.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:57f9d3a88b822e3727505cf0a59e4b1038de4cd34555749bdc65ac258a58ca23"}, - {file = "yappi-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f3fb92fe0ea47142275fbe6e5d1daa9685c2e25bfd6a9478c2669e8828b3abf8"}, - {file = "yappi-1.4.0-cp310-cp310-win32.whl", hash = "sha256:52b82a8ec9d5e86e828fe35821a8482c94ca1dec8a278bb8001d21f2c8af98a8"}, - {file = "yappi-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5767d79a44d47a34be469d798ddc56cff251394af1f4fde2463de9359a8c38e"}, - {file = "yappi-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8bc404a3201ec9dc93ab669a700b4f3736bbe3a029e85dc046f278541b83f74"}, - {file = "yappi-1.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:733b4088a54996e7811dca94de633ffe4b906b6e6b8147c31913b674ae6e90cc"}, - {file = "yappi-1.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5cd0ed067b4499fa45f08e78e0caf9154bc5ae28eca90167107b1fcfa741dac"}, - {file = "yappi-1.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:34aed429e1ef04d5b432bbbd719d7c7707b9fb310e30f78c61d0b31733626af8"}, - {file = "yappi-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01fc1f7f76a43a2d0ded34313c97395e3c3323e796945b183569a5a0365b14a3"}, - {file = "yappi-1.4.0-cp311-cp311-win32.whl", hash = "sha256:987c8f658e1d2e4029612c33a4ff7b04f9a8fbd96e315eefb0384943830ae68b"}, - {file = "yappi-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:4f42a9de88cfcbcd3f05834b4cc585e6e70ae0c4e03918b41865ccca02d2514b"}, - {file = "yappi-1.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a3bb2d75620ac9ef69f11c62e737469ef155e566e51ed85a74126871e45d2051"}, - {file = "yappi-1.4.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3033cdbd482a79ecafcafef8a1a0699ad333ee87bc7a28bd07c461ef196b2ea3"}, - {file = "yappi-1.4.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42ddd97258604bb1bea1b7dce2790c24f9b9bca970d844cb7afe98a9fbbf1425"}, - {file = "yappi-1.4.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:3a9652e7785f4b4c8bb3a8fa9ee33adf5e3f6dd893de4465008f75b1306f7895"}, - {file = "yappi-1.4.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:3e5d5a95a8681dc91f5a22c81d458109dcbcd718a551b647d28075574dfb8cbb"}, - {file = "yappi-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:89d352ea770860617f55539e860440a166c5b9c1a67a7f351fed4030af9943b0"}, - {file = "yappi-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:64529504c5522b1c8c79eeb27a68f84979ce9415150c32cd7e06618383443bcc"}, - {file = "yappi-1.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d878f66d0b5d79396d6f034f8d89615517a4c4410e97b84d48402e940f9501d5"}, - {file = "yappi-1.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bad0766003eaa683e56f77166d4551c2f7530ec13aa602ada5cd8ddfe130d42b"}, - {file = "yappi-1.4.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ab8c17980e6bdb522b03b118f6d62362c92f7be40a81a4e89746d0eeae1e3ab"}, - {file = "yappi-1.4.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:194a565ab0145ff10e31389fb364a35a4f5160ad6af17362355592cfddf2ae6e"}, - {file = "yappi-1.4.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:14068a34907f4e7404b6b87a7bda2d55be2bde4d4d7f9e254b2cd26187cc2ebc"}, - {file = "yappi-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:407b119f394ab60bb0a3d07efcb92d4846ef40ab40fff02c8902ca8d800f85d3"}, - {file = "yappi-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5e4de1137021f80a238217444c0ad5f0e393082f4744ecae3d92eb3a9b98ca3e"}, - {file = "yappi-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7b286c4fcc72812adbd19280329a3c0144582abd1e5a3513d93a8bb2d3d1abaa"}, - {file = "yappi-1.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aef7a5bd5cd7e36adb90419984f29809eee51c9a9b74849b9dfa6077075da21f"}, - {file = "yappi-1.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5092940caea4cc150ba21d9afbafc8b00770f33ab5de55638c2bbd2c6f7f82cf"}, - {file = "yappi-1.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ec8ada826232137560e6ac7644ace8305b4dacbca0f9fff246ffee52db0a3c3a"}, - {file = "yappi-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1413d3fb200c0011b22764a227fb9e56e479acb1ec2b7c134c62d70a76a7e1f2"}, - {file = "yappi-1.4.0-cp38-cp38-win32.whl", hash = "sha256:38b0235574b7c0c549d97baa63f5fa4660b6d34a0b00ee8cc48d04ef19cf71fb"}, - {file = "yappi-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ab23d95fe8130445f1e089af7efec21f172611b306283496c99089839ef61c5"}, - {file = "yappi-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:61a2c7dc15eeccd1909c6bc5783e63fb06ee7725e5aa006b83cd6afb49a343c7"}, - {file = "yappi-1.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c81d957b10085ce32bb232896d258e9e87ae4ac4e044e755eb505f1c8eb148da"}, - {file = "yappi-1.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e4a0af76310957d12ff2d661e2ec3509ee4b4661929fec04d0dc40a0c8866ae"}, - {file = "yappi-1.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a279bb01f9c4b4c99cb959210e49151afd6c76693eca8a01311343efe8f31262"}, - {file = "yappi-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:36eaa02d53842b22157f1b150db79d03cae1cc635f708fa82737bcdfd4aa2bd9"}, - {file = "yappi-1.4.0-cp39-cp39-win32.whl", hash = "sha256:05b2c6c7f0667b46cd7cccbd36cff1b10f4b3f6625aacea5eb0ac99cd9ca7520"}, - {file = "yappi-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:bbdd6043e24f5c84a042ea8af69a1f2720571426fd1985814cf41e6d7a17f5c9"}, - {file = "yappi-1.4.0.tar.gz", hash = "sha256:504b5d8fc7433736cb5e257991d2e7f2946019174f1faec7b2fe947881a17fc0"}, + {file = "yappi-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7c22bb39d3f2f294766f4940848d11b8ad1c43f9cf0a594ed695b07016007fc"}, + {file = "yappi-1.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:084688828c0a8c181ebe59bbf15dcd5a5db2f689eada59d5c277b997c4dccf43"}, + {file = "yappi-1.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23c668e9ce87d70b126f73970cff997a2ab1964b947859ee50580af23964a096"}, + {file = "yappi-1.6.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d4c7c5de3ae439c53c6c6c98d30d4b063c6fc353428ba3d81b57d91f1c41f654"}, + {file = "yappi-1.6.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:830ffb677b7a9f9886bc7789e9cb75d5b3ad9af5f43d56d48e56431f92f04bcc"}, + {file = "yappi-1.6.0-cp310-cp310-win32.whl", hash = "sha256:b42f7934fe96fd330488f9def51dd8e2fecc5cc9a71dceab8a27a41406b31332"}, + {file = "yappi-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:1cd7453e99ebf56491254b0f4c28ae95c5e0ce55043eb17d1ab02c974cbd7416"}, + {file = "yappi-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e9bc33b8ec9bce8b2575a4c3878b3cd223d08eb728669924699e5ac937e7b515"}, + {file = "yappi-1.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1cb70d46827a137350fb84b8fddecd7acec0a11834c763209875788b738f873"}, + {file = "yappi-1.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2cefe387bc747afcf0b26c9548e242113e17fac3de2674d900e97eb58a328f6"}, + {file = "yappi-1.6.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:acfbf4c80b6ee0513ad35a6e4a1f633aa2f93357517f9701aed6ad8cd56544d4"}, + {file = "yappi-1.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e4959c1dcfb6da8441d05915bfbb9c697e9f11655568f65b87c341e543bd65d5"}, + {file = "yappi-1.6.0-cp311-cp311-win32.whl", hash = "sha256:88dee431bba79866692f444110695133181efb2a6969ab63752f4424787f79c8"}, + {file = "yappi-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:8ddbe1475964f145b028f8bf120a58903d8f6c7bdd1be0a16c1471ba2d8646ca"}, + {file = "yappi-1.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1ba7d12c18bc0d092463ad126a95a1b2b8c261c47b0e3bd4cb2fd7479469141c"}, + {file = "yappi-1.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb5bbb4c6b996736554cb8f41e7fb6d5ee6096b7c4f54112cce8cf953a92c0a4"}, + {file = "yappi-1.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c12da5f310d81779056566259fef644a9c14ac1ec9a2b1b8a3fc62beb4ca6980"}, + {file = "yappi-1.6.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:677d992c41b239441eee399ac39ea7601010ddb5acb92bf997de7589f9ee2cc1"}, + {file = "yappi-1.6.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d58e60aac43041d109f0931917204ef02ac01004b9579fe173f2847fbc69655b"}, + {file = "yappi-1.6.0-cp312-cp312-win32.whl", hash = "sha256:a6797f189b7b89154d6c7c53ac769a22f0adb7bd88ea5b8f6c65106a286afad6"}, + {file = "yappi-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:cdaa263ba667aac9bf7bdc0d96fd10e2761a287f01fe87dc136f064ab7696af3"}, + {file = "yappi-1.6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:819c43539f55a9f40118ab8b3ce7cb743d66f3af63c7ce984c114533f750b263"}, + {file = "yappi-1.6.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1a8be1f55875e2120d7cddcb7e98c77a79ed87715d6292874c782fcd7da2c50"}, + {file = "yappi-1.6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0f82e4895d04d6fd7bed2bea0abcc84271bdd990371cb053132753b6f5afb73"}, + {file = "yappi-1.6.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1fd7d2da3e32f3d029220356e9b5b24754a7cd708d6e3830405e3dc04ec74153"}, + {file = "yappi-1.6.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2c7c2c9048b2f9fbd5da9cc65bdad73571023a30b5c34f62d97d9a7d47cbe9f5"}, + {file = "yappi-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:d9f6ac7cd8797850bb6fb4cef8364ed34051be6f47d7da74be3a9261eef4bbfb"}, + {file = "yappi-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6a16dd3fb61cfa7ffeb287312ddfe2a5c61a53693b009d3a7a3f1b8affb9568a"}, + {file = "yappi-1.6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:638bd2458a6dfaa278e8977a8fdf44c8626003c12d8c94d82338ef8aa6ac245f"}, + {file = "yappi-1.6.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30d294a88baffc3cb13a66fe408ecf8973c927fb3498f327df5af7cc657cdc80"}, + {file = "yappi-1.6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d49f972a8901972b104a2b65953ae8cbe005d5c09e0974422195bb780b2c5001"}, + {file = "yappi-1.6.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e40a872d146ddddae337181f8808aa6c3b37ffa66bd38a18f009b9e2f2c08b99"}, + {file = "yappi-1.6.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:31050972159a026876a06b5eec97f2dbaaaa291ebf3cf07a0d5506cce37ef339"}, + {file = "yappi-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:36278de1ecf3a781322fb5f9511abc0b66bff327ca87a9e868dc2e376ad1b11a"}, + {file = "yappi-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ef61f5fed7c19dddad5b7565df5b7bdfa861d51c15b01a90d283c4d3c97c42e2"}, + {file = "yappi-1.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e33c097402e101a51f9963654108e7625853ddc979b562e8381f761cce99ae13"}, + {file = "yappi-1.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9ea8dada24af41c11059f70741d8fce707aaf6862a9306f2ab63bde35f0ce9e"}, + {file = "yappi-1.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e37817722a052632de21674ec8acf59645c08df786920362879a76493037c99e"}, + {file = "yappi-1.6.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72aff63e74b87ffbf121211246922df9ac5dffc8deabdc6964f5b7f399799d0a"}, + {file = "yappi-1.6.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8a3c970f43f6d9bbc7159b535fbef492cb21576c094e77a673362ad827d9e00a"}, + {file = "yappi-1.6.0-cp38-cp38-win32.whl", hash = "sha256:69a4aced8c86bcc91fbecc3924ca9bd0a91ed715531c8a039199ef325ebb7046"}, + {file = "yappi-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:93352217bf560bea09b1cb43a17361bd2d41864698fa7ae46ce1066266c1af76"}, + {file = "yappi-1.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6678f046e6bffc68ef2d7781f9fc90b932ca6e90ea966371318ed904c4c38b8d"}, + {file = "yappi-1.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2f8f0877e3b85b6d2074d2fb541085cd519481f3df9c7e7011fc3867c364c7e"}, + {file = "yappi-1.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ae77cfe71682beec6f15ddd6dfb5912436c489b38eb2c3355f4481c07b9c4bf"}, + {file = "yappi-1.6.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:237b1ac310ef364db6d2a1817de93a346d1ed98abfa3053810dbbdcab9ca9300"}, + {file = "yappi-1.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:474e9f3ba9394c19dd2f7dc257123e3918c178638597d507ee2094f19d938a39"}, + {file = "yappi-1.6.0-cp39-cp39-win32.whl", hash = "sha256:a69ce9d7acc71419092f158ab4851d982e90ecbffbe6abf7d95516f3f741b57f"}, + {file = "yappi-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:e6ec9eabc974f9df868faa67461a9d167e9612083f59338f755f4aa61a2552b7"}, + {file = "yappi-1.6.0.tar.gz", hash = "sha256:a9aaf72009d8c03067294151ee0470ac7a6dfa7b33baab40b198d6c1ef00430a"}, ] [package.extras] @@ -2930,4 +3021,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.7.0" -content-hash = "95546ecc08755aca3157a1fb072c0e7623c2b6af8acc8d4e38fe7672239dca81" +content-hash = "4d0a640b3285716ffdad96bfe0ede753fce2a7de8ae978205c8d22f4808b7dd3" diff --git a/pyproject.toml b/pyproject.toml index 7200ce9c5..7ead1c8fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.7.0" databases = ">=0.3.2,!=0.5.0,!=0.5.1,!=0.5.2,!=0.5.3,<0.6.3" -pydantic = ">=v2.0b3" +pydantic = ">=v2.5.2" SQLAlchemy = ">=1.3.18,<1.4.42" cryptography = { version = ">=35,<42", optional = true } # Async database drivers diff --git a/tests/test_model_definition/test_aliases.py b/tests/test_model_definition/test_aliases.py index d403304fb..9f131dd42 100644 --- a/tests/test_model_definition/test_aliases.py +++ b/tests/test_model_definition/test_aliases.py @@ -12,10 +12,12 @@ class Child(ormar.Model): - class Meta: - tablename = "children" - metadata = metadata - database = database + + ormar_config = ormar.OrmarConfig( + tablename="children", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(name="child_id", primary_key=True) first_name: str = ormar.String(name="fname", max_length=100) @@ -24,10 +26,12 @@ class Meta: class Artist(ormar.Model): - class Meta: - tablename = "artists" - metadata = metadata - database = database + + ormar_config = ormar.OrmarConfig( + tablename="artists", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(name="artist_id", primary_key=True) first_name: str = ormar.String(name="fname", max_length=100) @@ -37,10 +41,11 @@ class Meta: class Album(ormar.Model): - class Meta: - tablename = "music_albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="music_albums", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(name="album_id", primary_key=True) name: str = ormar.String(name="album_name", max_length=100) @@ -57,11 +62,11 @@ def create_test_database(): def test_table_structure(): - assert "album_id" in [x.name for x in Album.Meta.table.columns] - assert "album_name" in [x.name for x in Album.Meta.table.columns] - assert "fname" in [x.name for x in Artist.Meta.table.columns] - assert "lname" in [x.name for x in Artist.Meta.table.columns] - assert "year" in [x.name for x in Artist.Meta.table.columns] + assert "album_id" in [x.name for x in Album.ormar_config.table.columns] + assert "album_name" in [x.name for x in Album.ormar_config.table.columns] + assert "fname" in [x.name for x in Artist.ormar_config.table.columns] + assert "lname" in [x.name for x in Artist.ormar_config.table.columns] + assert "year" in [x.name for x in Artist.ormar_config.table.columns] @pytest.mark.asyncio diff --git a/tests/test_model_definition/test_columns.py b/tests/test_model_definition/test_columns.py index 56c9c74c2..25eeb4135 100644 --- a/tests/test_model_definition/test_columns.py +++ b/tests/test_model_definition/test_columns.py @@ -24,10 +24,11 @@ class MyEnum(Enum): class Example(ormar.Model): - class Meta: - tablename = "example" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="example", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, default="aaa") @@ -41,10 +42,11 @@ class Meta: class EnumExample(ormar.Model): - class Meta: - tablename = "enum_example" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="enum_example", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) size: MyEnum = ormar.Enum(enum_class=MyEnum, default=MyEnum.SMALL) @@ -59,7 +61,7 @@ def create_test_database(): def test_proper_enum_column_type(): - assert Example.__fields__["size"].type_ == MyEnum + assert Example.model_fields["size"].__type__ == MyEnum def test_accepts_only_proper_enums(): @@ -135,10 +137,11 @@ async def test_invalid_enum_field(): with pytest.raises(ModelDefinitionError): class Example2(ormar.Model): - class Meta: - tablename = "example" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="example", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) size: MyEnum = ormar.Enum(enum_class=[]) diff --git a/tests/test_model_definition/test_create_uses_init_for_consistency.py b/tests/test_model_definition/test_create_uses_init_for_consistency.py index 544052708..02d431d9f 100644 --- a/tests/test_model_definition/test_create_uses_init_for_consistency.py +++ b/tests/test_model_definition/test_create_uses_init_for_consistency.py @@ -4,7 +4,7 @@ import databases import pytest import sqlalchemy -from pydantic import root_validator +from pydantic import model_validator, root_validator import ormar from tests.settings import DATABASE_URL @@ -13,19 +13,15 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata - - class Mol(ormar.Model): # fixed namespace to generate always unique uuid from the smiles _UUID_NAMESPACE: ClassVar[uuid.UUID] = uuid.UUID( "12345678-abcd-1234-abcd-123456789abc" ) - class Meta(BaseMeta): - tablename = "mols" + ormar_config = ormar.OrmarConfig( + database=database, metadata=metadata, tablename="mols" + ) id: uuid.UUID = ormar.UUID(primary_key=True, index=True, uuid_format="hex") smiles: str = ormar.String(nullable=False, unique=True, max_length=256) @@ -36,7 +32,7 @@ def __init__(self, **kwargs): kwargs["id"] = self._UUID_NAMESPACE super().__init__(**kwargs) - @root_validator() + @model_validator(mode="before") def make_canonical_smiles_and_uuid(cls, values): values["id"], values["smiles"] = cls.uuid(values["smiles"]) return values diff --git a/tests/test_model_definition/test_dates_with_timezone.py b/tests/test_model_definition/test_dates_with_timezone.py index afb6fbd71..670e8d17a 100644 --- a/tests/test_model_definition/test_dates_with_timezone.py +++ b/tests/test_model_definition/test_dates_with_timezone.py @@ -13,9 +13,10 @@ class DateFieldsModel(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) created_date: datetime = ormar.DateTime( @@ -29,27 +30,30 @@ class Meta: class SampleModel(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) updated_at: datetime = ormar.DateTime() class TimeModel(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) elapsed: time = ormar.Time() class DateModel(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) creation_date: date = ormar.Date() @@ -59,10 +63,9 @@ class MyModel(ormar.Model): id: int = ormar.Integer(primary_key=True) created_at: datetime = ormar.DateTime(timezone=True, nullable=False) - class Meta: - tablename = "mymodels" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="mymodels", metadata=metadata, database=database + ) @pytest.fixture(autouse=True, scope="module") diff --git a/tests/test_model_definition/test_equality_and_hash.py b/tests/test_model_definition/test_equality_and_hash.py index b0121667a..33a7607c8 100644 --- a/tests/test_model_definition/test_equality_and_hash.py +++ b/tests/test_model_definition/test_equality_and_hash.py @@ -12,10 +12,11 @@ class Song(ormar.Model): - class Meta: - tablename = "songs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="songs", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_model_definition/test_extra_ignore_parameter.py b/tests/test_model_definition/test_extra_ignore_parameter.py index cd3960c4d..a15c96f98 100644 --- a/tests/test_model_definition/test_extra_ignore_parameter.py +++ b/tests/test_model_definition/test_extra_ignore_parameter.py @@ -10,11 +10,12 @@ class Child(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "children" - metadata = metadata - database = database - extra = Extra.ignore + ormar_config = ormar.OrmarConfig( + tablename="children", + metadata=metadata, + database=database, + extra=Extra.ignore, + ) id: int = ormar.Integer(name="child_id", primary_key=True) first_name: str = ormar.String(name="fname", max_length=100) diff --git a/tests/test_model_definition/test_fields_access.py b/tests/test_model_definition/test_fields_access.py index 5140b3e54..b744a605e 100644 --- a/tests/test_model_definition/test_fields_access.py +++ b/tests/test_model_definition/test_fields_access.py @@ -10,22 +10,22 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class PriceList(ormar.Model): - class Meta(BaseMeta): - tablename = "price_lists" + + ormar_config = base_ormar_config.copy(tablename="price_lists") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -33,8 +33,7 @@ class Meta(BaseMeta): class Product(ormar.Model): - class Meta(BaseMeta): - tablename = "product" + ormar_config = base_ormar_config.copy(tablename="product") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -53,8 +52,8 @@ def create_test_database(): def test_fields_access(): # basic access - assert Product.id._field == Product.Meta.model_fields["id"] - assert Product.id.id == Product.Meta.model_fields["id"] + assert Product.id._field == Product.ormar_config.model_fields["id"] + assert Product.id.id == Product.ormar_config.model_fields["id"] assert Product.pk.id == Product.id.id assert isinstance(Product.id._field, BaseField) assert Product.id._access_chain == "id" @@ -62,19 +61,19 @@ def test_fields_access(): # nested models curr_field = Product.category.name - assert curr_field._field == Category.Meta.model_fields["name"] + assert curr_field._field == Category.ormar_config.model_fields["name"] assert curr_field._access_chain == "category__name" assert curr_field._source_model == Product # deeper nesting curr_field = Product.category.price_lists.name - assert curr_field._field == PriceList.Meta.model_fields["name"] + assert curr_field._field == PriceList.ormar_config.model_fields["name"] assert curr_field._access_chain == "category__price_lists__name" assert curr_field._source_model == Product # reverse nesting curr_field = PriceList.categories.products.rating - assert curr_field._field == Product.Meta.model_fields["rating"] + assert curr_field._field == Product.ormar_config.model_fields["rating"] assert curr_field._access_chain == "categories__products__rating" assert curr_field._source_model == PriceList diff --git a/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py b/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py index cc24cb400..354e02b6c 100644 --- a/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py +++ b/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py @@ -12,14 +12,14 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class PageLink(ormar.Model): - class Meta(BaseMeta): - tablename = "pagelinks" + ormar_config = base_ormar_config.copy(tablename="pagelinks") id: int = ormar.Integer(primary_key=True) value: str = ormar.String(max_length=2048) @@ -27,8 +27,7 @@ class Meta(BaseMeta): class Post(ormar.Model): - class Meta(BaseMeta): - tablename = "posts" + ormar_config = base_ormar_config.copy(tablename="posts") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=500) @@ -38,16 +37,14 @@ class Meta(BaseMeta): class Department(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4()) name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_model_definition/test_iterate.py b/tests/test_model_definition/test_iterate.py index 54fd32482..884650481 100644 --- a/tests/test_model_definition/test_iterate.py +++ b/tests/test_model_definition/test_iterate.py @@ -12,20 +12,22 @@ class User(ormar.Model): - class Meta: - tablename = "users3" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="users3", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="") class User2(ormar.Model): - class Meta: - tablename = "users4" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="users4", + metadata=metadata, + database=database, + ) id: uuid.UUID = ormar.UUID( uuid_format="string", primary_key=True, default=uuid.uuid4 @@ -34,10 +36,11 @@ class Meta: class Task(ormar.Model): - class Meta: - tablename = "tasks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="tasks", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="") @@ -45,10 +48,11 @@ class Meta: class Task2(ormar.Model): - class Meta: - tablename = "tasks2" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="tasks2", + metadata=metadata, + database=database, + ) id: uuid.UUID = ormar.UUID( uuid_format="string", primary_key=True, default=uuid.uuid4 diff --git a/tests/test_model_definition/test_model_construct.py b/tests/test_model_definition/test_model_construct.py index e2d7876ed..e51ee13fe 100644 --- a/tests/test_model_definition/test_model_construct.py +++ b/tests/test_model_definition/test_model_construct.py @@ -12,27 +12,30 @@ class NickNames(ormar.Model): - class Meta: - tablename = "nicks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="nicks", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") class NicksHq(ormar.Model): - class Meta: - tablename = "nicks_x_hq" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="nicks_x_hq", + metadata=metadata, + database=database, + ) class HQ(ormar.Model): - class Meta: - tablename = "hqs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="hqs", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -40,10 +43,11 @@ class Meta: class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="companies", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") diff --git a/tests/test_model_definition/test_model_definition.py b/tests/test_model_definition/test_model_definition.py index b0b2adfe0..4a8c68c22 100644 --- a/tests/test_model_definition/test_model_definition.py +++ b/tests/test_model_definition/test_model_definition.py @@ -16,15 +16,15 @@ from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() - database = databases.Database(DATABASE_URL, force_rollback=True) class ExampleModel(Model): - class Meta: - tablename = "example" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="example", + metadata=metadata, + database=database, + ) test: int = ormar.Integer(primary_key=True) test_string: str = ormar.String(max_length=250) @@ -55,10 +55,11 @@ class Meta: class ExampleModel2(Model): - class Meta: - tablename = "examples" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="examples", + metadata=metadata, + database=database, + ) test: int = ormar.Integer(primary_key=True) test_string: str = ormar.String(max_length=250) @@ -84,7 +85,7 @@ def example(): def test_not_nullable_field_is_required(): - with pytest.raises(pydantic.error_wrappers.ValidationError): + with pytest.raises(pydantic.ValidationError): ExampleModel(test=1, test_string="test") @@ -116,9 +117,10 @@ def test_missing_metadata(): with pytest.raises(ModelDefinitionError): class JsonSample2(ormar.Model): - class Meta: - tablename = "jsons2" - database = database + ormar_config = ormar.OrmarConfig( + tablename="jsons2", + database=database, + ) id: int = ormar.Integer(primary_key=True) test_json = ormar.JSON(nullable=True) @@ -128,8 +130,7 @@ def test_missing_database(): with pytest.raises(ModelDefinitionError): class JsonSample3(ormar.Model): - class Meta: - tablename = "jsons3" + ormar_config = ormar.OrmarConfig(tablename="jsons3") id: int = ormar.Integer(primary_key=True) test_json = ormar.JSON(nullable=True) @@ -155,8 +156,10 @@ def test_pydantic_model_is_created(example): def test_sqlalchemy_table_is_created(example): - assert issubclass(example.Meta.table.__class__, sqlalchemy.Table) - assert all([field in example.Meta.table.columns for field in fields_to_check]) + assert issubclass(example.ormar_config.table.__class__, sqlalchemy.Table) + assert all( + [field in example.ormar_config.table.columns for field in fields_to_check] + ) @typing.no_type_check @@ -164,10 +167,11 @@ def test_no_pk_in_model_definition(): with pytest.raises(ModelDefinitionError): # type: ignore class ExampleModel2(Model): # type: ignore - class Meta: - tablename = "example2" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="example2", + database=database, + metadata=metadata, + ) test_string: str = ormar.String(max_length=250) # type: ignore @@ -178,10 +182,11 @@ def test_two_pks_in_model_definition(): @typing.no_type_check class ExampleModel2(Model): - class Meta: - tablename = "example3" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="example3", + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) test_string: str = ormar.String(max_length=250, primary_key=True) @@ -192,10 +197,11 @@ def test_setting_pk_column_as_pydantic_only_in_model_definition(): with pytest.raises(ModelDefinitionError): class ExampleModel2(Model): - class Meta: - tablename = "example4" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="example4", + database=database, + metadata=metadata, + ) test: int = ormar.Integer(primary_key=True, pydantic_only=True) @@ -205,10 +211,11 @@ def test_decimal_error_in_model_definition(): with pytest.raises(ModelDefinitionError): class ExampleModel2(Model): - class Meta: - tablename = "example5" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="example5", + database=database, + metadata=metadata, + ) test: decimal.Decimal = ormar.Decimal(primary_key=True) @@ -218,10 +225,11 @@ def test_binary_error_without_length_model_definition(): with pytest.raises(ModelDefinitionError): class ExampleModel2(Model): - class Meta: - tablename = "example6" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="example6", + database=database, + metadata=metadata, + ) test: bytes = ormar.LargeBinary(primary_key=True, max_length=-1) @@ -231,10 +239,11 @@ def test_string_error_in_model_definition(): with pytest.raises(ModelDefinitionError): class ExampleModel2(Model): - class Meta: - tablename = "example6" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="example6", + database=database, + metadata=metadata, + ) test: str = ormar.String(primary_key=True, max_length=0) diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index d5e911a0d..5a02bb02a 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -3,6 +3,7 @@ import datetime import os import uuid +from enum import Enum, Flag from typing import List import databases @@ -19,10 +20,11 @@ class JsonSample(ormar.Model): - class Meta: - tablename = "jsons" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="jsons", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) test_json = ormar.JSON(nullable=True) @@ -33,10 +35,11 @@ class Meta: class LargeBinarySample(ormar.Model): - class Meta: - tablename = "my_bolbs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="my_bolbs", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) test_binary: bytes = ormar.LargeBinary(max_length=100000, choices=[blob, blob2]) @@ -47,10 +50,11 @@ class Meta: class LargeBinaryStr(ormar.Model): - class Meta: - tablename = "my_str_blobs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="my_str_blobs", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) test_binary: str = ormar.LargeBinary( @@ -59,10 +63,11 @@ class Meta: class LargeBinaryNullableStr(ormar.Model): - class Meta: - tablename = "my_str_blobs2" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="my_str_blobs2", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) test_binary: str = ormar.LargeBinary( @@ -74,20 +79,22 @@ class Meta: class UUIDSample(ormar.Model): - class Meta: - tablename = "uuids" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="uuids", + metadata=metadata, + database=database, + ) id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) test_text: str = ormar.Text() class UUIDSample2(ormar.Model): - class Meta: - tablename = "uuids2" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="uuids2", + metadata=metadata, + database=database, + ) id: uuid.UUID = ormar.UUID( primary_key=True, default=uuid.uuid4, uuid_format="string" @@ -96,77 +103,88 @@ class Meta: class User(ormar.Model): - class Meta: - tablename = "users" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="users", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="") class User2(ormar.Model): - class Meta: - tablename = "users2" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="users2", + metadata=metadata, + database=database, + ) id: str = ormar.String(primary_key=True, max_length=100) name: str = ormar.String(max_length=100, default="") class Product(ormar.Model): - class Meta: - tablename = "product" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="product", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) rating: int = ormar.Integer(minimum=1, maximum=5) in_stock: bool = ormar.Boolean(default=False) - last_delivery: datetime.date = ormar.Date(default=datetime.datetime.now) + last_delivery: datetime.date = ormar.Date(default=datetime.date.today) + + +class CountryNameEnum(Enum): + CANADA = "Canada" + ALGERIA = "Algeria" + USA = "United States" + BELIZE = "Belize" -country_name_choices = ("Canada", "Algeria", "United States", "Belize") -country_taxed_choices = (True,) -country_country_code_choices = (-10, 1, 213, 1200) +class CountryCodeEnum(int, Enum): + MINUS_TEN = -10 + ONE = 1 + TWO_HUNDRED_THIRTEEN = 213 + THOUSAND_TWO_HUNDRED = 1200 class Country(ormar.Model): - class Meta: - tablename = "country" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="country", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) - name: str = ormar.String( - max_length=9, choices=country_name_choices, default="Canada" - ) - taxed: bool = ormar.Boolean(choices=country_taxed_choices, default=True) - country_code: int = ormar.Integer( - minimum=0, maximum=1000, choices=country_country_code_choices, default=1 - ) + name: str = ormar.Enum(enum_class=CountryNameEnum, default="Canada") + taxed: bool = ormar.Boolean(default=True) + country_code: int = ormar.Enum(enum_class=CountryCodeEnum, default=1) class NullableCountry(ormar.Model): - class Meta: - tablename = "country2" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="country2", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) - name: str = ormar.String(max_length=9, choices=country_name_choices, nullable=True) + name: str = ormar.Enum(enum_class=CountryNameEnum, nullable=True) class NotNullableCountry(ormar.Model): - class Meta: - tablename = "country3" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="country3", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) - name: str = ormar.String(max_length=9, choices=country_name_choices, nullable=False) + name: str = ormar.Enum(enum_class=CountryNameEnum, nullable=False) @pytest.fixture(autouse=True, scope="module") @@ -179,12 +197,14 @@ def create_test_database(): def test_model_class(): - assert list(User.Meta.model_fields.keys()) == ["id", "name"] - assert issubclass(User.Meta.model_fields["id"].__class__, pydantic.fields.FieldInfo) - assert User.Meta.model_fields["id"].primary_key is True - assert isinstance(User.Meta.model_fields["name"], pydantic.fields.FieldInfo) - assert User.Meta.model_fields["name"].max_length == 100 - assert isinstance(User.Meta.table, sqlalchemy.Table) + assert list(User.ormar_config.model_fields.keys()) == ["id", "name"] + assert issubclass( + User.ormar_config.model_fields["id"].__class__, pydantic.fields.FieldInfo + ) + assert User.ormar_config.model_fields["id"].primary_key is True + assert isinstance(User.ormar_config.model_fields["name"], pydantic.fields.FieldInfo) + assert User.ormar_config.model_fields["name"].max_length == 100 + assert isinstance(User.ormar_config.table, sqlalchemy.Table) def test_wrong_field_name(): @@ -508,14 +528,6 @@ def contains(a, b): return a in b -def check_choices(values: tuple, ops: List): - ops_dict = {"in": contains, "out": not_contains} - checks = (country_name_choices, country_taxed_choices, country_country_code_choices) - assert all( - [ops_dict[op](value, check) for value, op, check in zip(values, ops, checks)] - ) - - @pytest.mark.asyncio async def test_model_choices(): """Test that choices work properly for various types of fields.""" @@ -529,54 +541,12 @@ async def test_model_choices(): with pytest.raises(ValueError): name, taxed, country_code = "Saudi Arabia", True, 1 - check_choices((name, taxed, country_code), ["out", "in", "in"]) - await Country.objects.create( - name=name, taxed=taxed, country_code=country_code - ) - - with pytest.raises(ValueError): - name, taxed, country_code = "Algeria", False, 1 - check_choices((name, taxed, country_code), ["in", "out", "in"]) await Country.objects.create( name=name, taxed=taxed, country_code=country_code ) with pytest.raises(ValueError): name, taxed, country_code = "Algeria", True, 967 - check_choices((name, taxed, country_code), ["in", "in", "out"]) - await Country.objects.create( - name=name, taxed=taxed, country_code=country_code - ) - - with pytest.raises(ValueError): - name, taxed, country_code = ( - "United States", - True, - 1, - ) # name is too long but is a valid choice - check_choices((name, taxed, country_code), ["in", "in", "in"]) - await Country.objects.create( - name=name, taxed=taxed, country_code=country_code - ) - - with pytest.raises(ValueError): - name, taxed, country_code = ( - "Algeria", - True, - -10, - ) # country code is too small but is a valid choice - check_choices((name, taxed, country_code), ["in", "in", "in"]) - await Country.objects.create( - name=name, taxed=taxed, country_code=country_code - ) - - with pytest.raises(ValueError): - name, taxed, country_code = ( - "Algeria", - True, - 1200, - ) # country code is too large but is a valid choice - check_choices((name, taxed, country_code), ["in", "in", "in"]) await Country.objects.create( name=name, taxed=taxed, country_code=country_code ) @@ -584,26 +554,16 @@ async def test_model_choices(): # test setting after init also triggers validation with pytest.raises(ValueError): name, taxed, country_code = "Algeria", True, 967 - check_choices((name, taxed, country_code), ["in", "in", "out"]) country = Country() country.country_code = country_code with pytest.raises(ValueError): name, taxed, country_code = "Saudi Arabia", True, 1 - check_choices((name, taxed, country_code), ["out", "in", "in"]) country = Country() country.name = name - with pytest.raises(ValueError): - name, taxed, country_code = "Algeria", False, 1 - check_choices((name, taxed, country_code), ["in", "out", "in"]) - country = Country() - country.taxed = taxed - # check also update from queryset with pytest.raises(ValueError): - name, taxed, country_code = "Algeria", False, 1 - check_choices((name, taxed, country_code), ["in", "out", "in"]) await Country(name="Belize").save() await Country.objects.filter(name="Belize").update(name="Vietnam") @@ -681,4 +641,4 @@ async def test_get_and_first(): def test_constraints(): with pytest.raises(pydantic.ValidationError) as e: Product(name="T-Shirt", rating=50, in_stock=True) - assert "ensure this value is less than or equal to 5" in str(e.value) + assert "Input should be less than or equal to 5 " in str(e.value) diff --git a/tests/test_model_definition/test_models_are_pickable.py b/tests/test_model_definition/test_models_are_pickable.py index bb05e02a6..61bd941ab 100644 --- a/tests/test_model_definition/test_models_are_pickable.py +++ b/tests/test_model_definition/test_models_are_pickable.py @@ -13,10 +13,11 @@ class User(ormar.Model): - class Meta: - tablename = "users" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="users", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -24,10 +25,11 @@ class Meta: class Post(ormar.Model): - class Meta: - tablename = "posts" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="posts", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_model_definition/test_overwriting_pydantic_field_type.py b/tests/test_model_definition/test_overwriting_pydantic_field_type.py index bb015a3e8..1c5824651 100644 --- a/tests/test_model_definition/test_overwriting_pydantic_field_type.py +++ b/tests/test_model_definition/test_overwriting_pydantic_field_type.py @@ -13,16 +13,15 @@ class OverwriteTest(ormar.Model): - class Meta: - tablename = "overwrites" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="overwrites", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) my_int: int = ormar.Integer(overwrite_pydantic_type=PositiveInt) - constraint_dict: Json = ormar.JSON( - overwrite_pydantic_type=Optional[Json[Dict[str, int]]] # type: ignore - ) + constraint_dict: Json = ormar.JSON(overwrite_pydantic_type=Optional[Json[Dict[str, int]]]) # type: ignore @pytest.fixture(autouse=True, scope="module") @@ -37,11 +36,14 @@ def create_test_database(): def test_constraints(): with pytest.raises(ValidationError) as e: OverwriteTest(my_int=-10) - assert "ensure this value is greater than 0" in str(e.value) + assert "Input should be greater than 0" in str(e.value) with pytest.raises(ValidationError) as e: OverwriteTest(my_int=10, constraint_dict={"aa": "ab"}) - assert "value is not a valid integer" in str(e.value) + assert ( + "Input should be a valid integer, unable to parse string as an integer" + in str(e.value) + ) @pytest.mark.asyncio diff --git a/tests/test_model_definition/test_overwriting_sql_nullable.py b/tests/test_model_definition/test_overwriting_sql_nullable.py index f98b45bfe..71c57c2b5 100644 --- a/tests/test_model_definition/test_overwriting_sql_nullable.py +++ b/tests/test_model_definition/test_overwriting_sql_nullable.py @@ -16,14 +16,14 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = db +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=db, +) class PrimaryModel(ormar.Model): - class Meta(BaseMeta): - tablename = "primary_models" + ormar_config = base_ormar_config.copy(tablename="primary_models") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) diff --git a/tests/test_model_definition/test_pk_field_is_always_not_null.py b/tests/test_model_definition/test_pk_field_is_always_not_null.py index 22b03a38f..f32eb0c74 100644 --- a/tests/test_model_definition/test_pk_field_is_always_not_null.py +++ b/tests/test_model_definition/test_pk_field_is_always_not_null.py @@ -8,32 +8,30 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class AutoincrementModel(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) class NonAutoincrementModel(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True, autoincrement=False) class ExplicitNullableModel(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True, nullable=True) def test_pk_field_is_not_null(): for model in [AutoincrementModel, NonAutoincrementModel, ExplicitNullableModel]: - assert not model.Meta.table.c.get("id").nullable + assert not model.ormar_config.table.c.get("id").nullable diff --git a/tests/test_model_definition/test_properties.py b/tests/test_model_definition/test_properties.py index 6456c6a95..200e8904f 100644 --- a/tests/test_model_definition/test_properties.py +++ b/tests/test_model_definition/test_properties.py @@ -12,10 +12,11 @@ class Song(ormar.Model): - class Meta: - tablename = "songs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="songs", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_model_definition/test_pydantic_fields.py b/tests/test_model_definition/test_pydantic_fields.py index 12d575379..775ae3b4a 100644 --- a/tests/test_model_definition/test_pydantic_fields.py +++ b/tests/test_model_definition/test_pydantic_fields.py @@ -12,20 +12,19 @@ database = databases.Database(DATABASE_URL) metadata = sqlalchemy.MetaData() - -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class ModelTest(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200) url: HttpUrl = "https://www.example.com" # type: ignore - number: Optional[PaymentCardNumber] + number: Optional[PaymentCardNumber] = None CARD_NUMBERS = [ @@ -42,8 +41,7 @@ def get_number(): class ModelTest2(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200) @@ -57,8 +55,7 @@ class PydanticTest(BaseModel): class ModelTest3(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() def __init__(self, **kwargs): kwargs["number"] = get_number() diff --git a/tests/test_model_definition/test_pydantic_only_fields.py b/tests/test_model_definition/test_pydantic_only_fields.py index ee5817799..e96f45c03 100644 --- a/tests/test_model_definition/test_pydantic_only_fields.py +++ b/tests/test_model_definition/test_pydantic_only_fields.py @@ -13,10 +13,11 @@ class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="albums", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_model_definition/test_pydantic_private_attributes.py b/tests/test_model_definition/test_pydantic_private_attributes.py index 2765f60e6..c4a066ff5 100644 --- a/tests/test_model_definition/test_pydantic_private_attributes.py +++ b/tests/test_model_definition/test_pydantic_private_attributes.py @@ -11,14 +11,14 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Subscription(ormar.Model): - class Meta(BaseMeta): - tablename = "subscriptions" + ormar_config = base_ormar_config.copy(tablename="subscriptions") id: int = ormar.Integer(primary_key=True) stripe_subscription_id: str = ormar.String(nullable=False, max_length=256) diff --git a/tests/test_model_definition/test_save_status.py b/tests/test_model_definition/test_save_status.py index b104072e6..7efd45491 100644 --- a/tests/test_model_definition/test_save_status.py +++ b/tests/test_model_definition/test_save_status.py @@ -13,10 +13,11 @@ class NickNames(ormar.Model): - class Meta: - tablename = "nicks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="nicks", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -24,17 +25,19 @@ class Meta: class NicksHq(ormar.Model): - class Meta: - tablename = "nicks_x_hq" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="nicks_x_hq", + metadata=metadata, + database=database, + ) class HQ(ormar.Model): - class Meta: - tablename = "hqs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="hqs", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -42,10 +45,11 @@ class Meta: class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="companies", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") diff --git a/tests/test_model_definition/test_saving_nullable_fields.py b/tests/test_model_definition/test_saving_nullable_fields.py index 0803b20e8..09618eb1b 100644 --- a/tests/test_model_definition/test_saving_nullable_fields.py +++ b/tests/test_model_definition/test_saving_nullable_fields.py @@ -14,10 +14,11 @@ class PrimaryModel(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "primary_models" + ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=db, + tablename="primary_models", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) @@ -27,10 +28,11 @@ class Meta: class SecondaryModel(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "secondary_models" + ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=db, + tablename="secondary_models", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_model_definition/test_server_default.py b/tests/test_model_definition/test_server_default.py index a9530688c..877d9f29f 100644 --- a/tests/test_model_definition/test_server_default.py +++ b/tests/test_model_definition/test_server_default.py @@ -15,10 +15,11 @@ class Product(ormar.Model): - class Meta: - tablename = "product" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="product", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -37,9 +38,11 @@ def create_test_database(): def test_table_defined_properly(): - assert Product.Meta.model_fields["created"].nullable - assert not Product.__fields__["created"].required - assert Product.Meta.table.columns["created"].server_default.arg.name == "now" + assert Product.ormar_config.model_fields["created"].nullable + assert not Product.model_fields["created"].is_required() + assert ( + Product.ormar_config.table.columns["created"].server_default.arg.name == "now" + ) @pytest.mark.asyncio diff --git a/tests/test_model_definition/test_setting_comments_in_db.py b/tests/test_model_definition/test_setting_comments_in_db.py index 588cdf19d..4c1f08a0f 100644 --- a/tests/test_model_definition/test_setting_comments_in_db.py +++ b/tests/test_model_definition/test_setting_comments_in_db.py @@ -12,10 +12,11 @@ class Comment(Model): - class Meta(ormar.ModelMeta): - tablename = "comments" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="comments", + metadata=metadata, + database=database, + ) test: int = ormar.Integer(primary_key=True, comment="primary key of comments") test_string: str = ormar.String(max_length=250, comment="test that it works") @@ -31,6 +32,6 @@ def create_test_database(): @pytest.mark.asyncio async def test_comments_are_set_in_db(): - columns = Comment.Meta.table.c + columns = Comment.ormar_config.table.c for c in columns: - assert c.comment == Comment.Meta.model_fields[c.name].comment + assert c.comment == Comment.ormar_config.model_fields[c.name].comment diff --git a/tests/test_types.py b/tests/test_types.py index b55a8f330..3997a1678 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,10 +1,12 @@ -from typing import Any, Optional, TYPE_CHECKING +from typing import Any, Optional, TYPE_CHECKING, TypedDict import databases import pytest import sqlalchemy import ormar +from ormar.models.metaclass import ModelMeta +from ormar.models.ormar_config import OrmarConfig from ormar.relations.querysetproxy import QuerysetProxy from tests.settings import DATABASE_URL @@ -14,10 +16,10 @@ class Publisher(ormar.Model): - model_config = dict( + ormar_config = OrmarConfig( metadata=metadata, database=database, - table_name="publishers", + tablename="publishers", ) id: int = ormar.Integer(primary_key=True) @@ -26,8 +28,8 @@ class Publisher(ormar.Model): class Author(ormar.Model): - model_config = dict( - metadata=metadata, database=database, table_name="authors", order_by=["-name"] + ormar_config = OrmarConfig( + metadata=metadata, database=database, tablename="authors", order_by=["-name"] ) id: int = ormar.Integer(primary_key=True) @@ -37,10 +39,10 @@ class Author(ormar.Model): class Book(ormar.Model): - model_config = dict( + ormar_config = OrmarConfig( metadata=metadata, database=database, - table_name="books", + tablename="books", order_by=["year", "-ranking"], ) From a1204d8916bc75bf77999d0cf3a0c4c684992f97 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 13 Dec 2023 17:08:16 +0100 Subject: [PATCH 03/95] WIP - make test_model_methods pass --- docs_src/relations/docs004.py | 7 +-- .../test_excludable_items.py | 7 +-- tests/test_fastapi/test_m2m_forwardref.py | 7 +-- .../test_fastapi/test_skip_reverse_models.py | 7 +-- tests/test_fastapi/test_wekref_exclusion.py | 7 +-- .../test_inheritance_with_default.py | 7 +-- .../test_pydantic_fields_order.py | 7 +-- .../test_validators_are_inherited.py | 7 +-- .../test_validators_in_generated_pydantic.py | 7 +-- .../pks_and_fks/test_non_integer_pkey.py | 9 ++-- .../pks_and_fks/test_saving_string_pks.py | 13 +++-- .../pks_and_fks/test_uuid_fks.py | 18 ++++--- .../test_excludes_in_load_all.py | 31 ++++------- tests/test_model_methods/test_load_all.py | 7 +-- .../test_populate_default_values.py | 10 ++-- tests/test_model_methods/test_save_related.py | 53 ++++++++++--------- .../test_save_related_from_dict.py | 49 +++++++++-------- .../test_save_related_uuid.py | 25 ++++----- tests/test_model_methods/test_update.py | 26 +++++---- tests/test_model_methods/test_upsert.py | 28 +++++----- .../test_values_and_values_list.py | 7 +-- .../test_relations/test_m2m_through_fields.py | 7 +-- tests/test_relations/test_skipping_reverse.py | 7 +-- 23 files changed, 180 insertions(+), 173 deletions(-) diff --git a/docs_src/relations/docs004.py b/docs_src/relations/docs004.py index 9a3b0c067..8b76059b0 100644 --- a/docs_src/relations/docs004.py +++ b/docs_src/relations/docs004.py @@ -1,6 +1,7 @@ -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Category(ormar.Model): diff --git a/tests/test_exclude_include_dict/test_excludable_items.py b/tests/test_exclude_include_dict/test_excludable_items.py index 66d3b8708..c59b9154a 100644 --- a/tests/test_exclude_include_dict/test_excludable_items.py +++ b/tests/test_exclude_include_dict/test_excludable_items.py @@ -11,9 +11,10 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class NickNames(ormar.Model): diff --git a/tests/test_fastapi/test_m2m_forwardref.py b/tests/test_fastapi/test_m2m_forwardref.py index e50c8359e..61784e071 100644 --- a/tests/test_fastapi/test_m2m_forwardref.py +++ b/tests/test_fastapi/test_m2m_forwardref.py @@ -34,9 +34,10 @@ async def shutdown() -> None: await database_.disconnect() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) CityRef = ForwardRef("City") diff --git a/tests/test_fastapi/test_skip_reverse_models.py b/tests/test_fastapi/test_skip_reverse_models.py index 3b28e057b..9aa20f1b6 100644 --- a/tests/test_fastapi/test_skip_reverse_models.py +++ b/tests/test_fastapi/test_skip_reverse_models.py @@ -32,9 +32,10 @@ async def shutdown() -> None: await database_.disconnect() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): diff --git a/tests/test_fastapi/test_wekref_exclusion.py b/tests/test_fastapi/test_wekref_exclusion.py index 989ba2b6f..c93b7a892 100644 --- a/tests/test_fastapi/test_wekref_exclusion.py +++ b/tests/test_fastapi/test_wekref_exclusion.py @@ -42,9 +42,10 @@ def create_test_database(): metadata.drop_all(engine) -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class OtherThing(ormar.Model): diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py index 1c61e410c..97ab138c9 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py @@ -12,9 +12,10 @@ database = databases.Database(DATABASE_URL) -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class BaseModel(ormar.Model): diff --git a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py index ffc515e69..0169bec63 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py +++ b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py @@ -9,9 +9,10 @@ database = databases.Database(DATABASE_URL) -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class NewTestModel(ormar.Model): diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py index eafce4097..1ff7c00b7 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py @@ -13,9 +13,10 @@ database = databases.Database(DATABASE_URL) -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class BaseModel(ormar.Model): diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py index d105481f8..6f5813fb5 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py @@ -14,9 +14,10 @@ database = databases.Database(DATABASE_URL) -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class EnumExample(str, enum.Enum): diff --git a/tests/test_model_definition/pks_and_fks/test_non_integer_pkey.py b/tests/test_model_definition/pks_and_fks/test_non_integer_pkey.py index 78fb179c7..4485f51fc 100644 --- a/tests/test_model_definition/pks_and_fks/test_non_integer_pkey.py +++ b/tests/test_model_definition/pks_and_fks/test_non_integer_pkey.py @@ -16,10 +16,11 @@ def key(): class Model(ormar.Model): - class Meta: - tablename = "models" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="models", + metadata=metadata, + database=database, + ) id: str = ormar.String(primary_key=True, default=key, max_length=8) name: str = ormar.String(max_length=32) diff --git a/tests/test_model_definition/pks_and_fks/test_saving_string_pks.py b/tests/test_model_definition/pks_and_fks/test_saving_string_pks.py index 01085c0aa..bd4dadcff 100644 --- a/tests/test_model_definition/pks_and_fks/test_saving_string_pks.py +++ b/tests/test_model_definition/pks_and_fks/test_saving_string_pks.py @@ -19,14 +19,14 @@ def get_id() -> str: return "".join(choice(ascii_uppercase) for _ in range(12)) -class MainMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class PositionOrm(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = base_ormar_config.copy() name: str = String(primary_key=True, max_length=50) x: float = Float() @@ -35,8 +35,7 @@ class Meta(MainMeta): class PositionOrmDef(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = base_ormar_config.copy() name: str = String(primary_key=True, max_length=50, default=get_id) x: float = Float() diff --git a/tests/test_model_definition/pks_and_fks/test_uuid_fks.py b/tests/test_model_definition/pks_and_fks/test_uuid_fks.py index 97f728ab4..9aacf1ae8 100644 --- a/tests/test_model_definition/pks_and_fks/test_uuid_fks.py +++ b/tests/test_model_definition/pks_and_fks/test_uuid_fks.py @@ -13,10 +13,11 @@ class User(ormar.Model): - class Meta: - tablename = "user" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "user", + metadata = metadata, + database = db, + ) id: uuid.UUID = ormar.UUID( primary_key=True, default=uuid.uuid4, uuid_format="string" @@ -29,10 +30,11 @@ class Meta: class Token(ormar.Model): - class Meta: - tablename = "token" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "token", + metadata = metadata, + database = db, + ) id = ormar.Integer(primary_key=True) text = ormar.String(max_length=4, unique=True) diff --git a/tests/test_model_methods/test_excludes_in_load_all.py b/tests/test_model_methods/test_excludes_in_load_all.py index 66ee8347a..ad11e3267 100644 --- a/tests/test_model_methods/test_excludes_in_load_all.py +++ b/tests/test_model_methods/test_excludes_in_load_all.py @@ -13,42 +13,31 @@ metadata = sqlalchemy.MetaData() -class BaseMeta: - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class JimmyUser(ormar.Model): - class Meta(BaseMeta): - tablename = "jimmy_users" + ormar_config = base_ormar_config.copy(tablename="jimmy_users") - id: uuid.UUID = ormar.UUID( - primary_key=True, default=uuid.uuid4(), uuid_format="string" - ) + id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4(), uuid_format="string") class JimmyProfile(ormar.Model): - class Meta(BaseMeta): - tablename = "jimmy_profiles" + ormar_config = base_ormar_config.copy(tablename="jimmy_profiles") - id: uuid.UUID = ormar.UUID( - primary_key=True, default=uuid.uuid4(), uuid_format="string" - ) + id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4(), uuid_format="string") name = ormar.String(max_length=42, default="JimmyProfile") - user: JimmyUser = ormar.ForeignKey(to=JimmyUser) class JimmyAccount(ormar.Model): - class Meta(BaseMeta): - tablename = "jimmy_accounts" - - id: uuid.UUID = ormar.UUID( - primary_key=True, default=uuid.uuid4(), uuid_format="string" - ) + ormar_config = base_ormar_config.copy(tablename="jimmy_accounts") + id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4(), uuid_format="string") name = ormar.String(max_length=42, default="JimmyAccount") - user: JimmyUser = ormar.ForeignKey(to=JimmyUser) diff --git a/tests/test_model_methods/test_load_all.py b/tests/test_model_methods/test_load_all.py index 0095654ae..a6d3aaf98 100644 --- a/tests/test_model_methods/test_load_all.py +++ b/tests/test_model_methods/test_load_all.py @@ -11,9 +11,10 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Language(ormar.Model): diff --git a/tests/test_model_methods/test_populate_default_values.py b/tests/test_model_methods/test_populate_default_values.py index b3cd2b65d..3bdc6b3ab 100644 --- a/tests/test_model_methods/test_populate_default_values.py +++ b/tests/test_model_methods/test_populate_default_values.py @@ -10,14 +10,14 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Task(ormar.Model): - class Meta(BaseMeta): - tablename = "tasks" + ormar_config = base_ormar_config.copy(tablename="tasks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String( diff --git a/tests/test_model_methods/test_save_related.py b/tests/test_model_methods/test_save_related.py index 207c53da3..3236cac77 100644 --- a/tests/test_model_methods/test_save_related.py +++ b/tests/test_model_methods/test_save_related.py @@ -12,20 +12,22 @@ class CringeLevel(ormar.Model): - class Meta: - tablename = "levels" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="levels", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class NickName(ormar.Model): - class Meta: - tablename = "nicks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="nicks", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -34,17 +36,19 @@ class Meta: class NicksHq(ormar.Model): - class Meta: - tablename = "nicks_x_hq" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="nicks_x_hq", + metadata=metadata, + database=database, + ) class HQ(ormar.Model): - class Meta: - tablename = "hqs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="hqs", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -52,10 +56,11 @@ class Meta: class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="companies", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -189,12 +194,8 @@ async def test_saving_nested(): async with database.transaction(force_rollback=True): level = await CringeLevel.objects.create(name="High") level2 = await CringeLevel.objects.create(name="Low") - nick1 = await NickName.objects.create( - name="BazingaO", is_lame=False, level=level - ) - nick2 = await NickName.objects.create( - name="Bazinga20", is_lame=True, level=level2 - ) + nick1 = await NickName.objects.create(name="BazingaO", is_lame=False, level=level) + nick2 = await NickName.objects.create(name="Bazinga20", is_lame=True, level=level2) hq = await HQ.objects.create(name="Main") assert hq.saved diff --git a/tests/test_model_methods/test_save_related_from_dict.py b/tests/test_model_methods/test_save_related_from_dict.py index a54509261..e76dde3dd 100644 --- a/tests/test_model_methods/test_save_related_from_dict.py +++ b/tests/test_model_methods/test_save_related_from_dict.py @@ -12,20 +12,22 @@ class CringeLevel(ormar.Model): - class Meta: - tablename = "levels" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="levels", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class NickName(ormar.Model): - class Meta: - tablename = "nicks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="nicks", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -34,20 +36,22 @@ class Meta: class NicksHq(ormar.Model): - class Meta: - tablename = "nicks_x_hq" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="nicks_x_hq", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) new_field: str = ormar.String(max_length=200, nullable=True) class HQ(ormar.Model): - class Meta: - tablename = "hqs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="hqs", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -55,10 +59,11 @@ class Meta: class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="companies", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -241,9 +246,7 @@ async def test_saving_nested_with_m2m_and_rev_fk_and_through(): count = await company.save_related(follow=True, save_all=True) assert count == 6 - company_check = await Company.objects.select_related( - "hq__nicks__level" - ).get() + company_check = await Company.objects.select_related("hq__nicks__level").get() assert company_check.pk is not None assert company_check.name == "Main" assert company_check.hq.name == "Yoko" diff --git a/tests/test_model_methods/test_save_related_uuid.py b/tests/test_model_methods/test_save_related_uuid.py index 602d1bd06..3dbb16d87 100644 --- a/tests/test_model_methods/test_save_related_uuid.py +++ b/tests/test_model_methods/test_save_related_uuid.py @@ -13,18 +13,20 @@ class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) department_name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) course_name: str = ormar.String(max_length=100) @@ -33,9 +35,10 @@ class Meta: class Student(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.String(max_length=100) @@ -72,9 +75,7 @@ async def test_uuid_pk_in_save_related(): department = Department(**to_save) await department.save_related(follow=True, save_all=True) department_check = ( - await Department.objects.select_all(follow=True) - .order_by(Department.courses.students.name.asc()) - .get() + await Department.objects.select_all(follow=True).order_by(Department.courses.students.name.asc()).get() ) to_exclude = { "id": ..., diff --git a/tests/test_model_methods/test_update.py b/tests/test_model_methods/test_update.py index 391baf707..0b6fd635f 100644 --- a/tests/test_model_methods/test_update.py +++ b/tests/test_model_methods/test_update.py @@ -12,10 +12,11 @@ class Director(ormar.Model): - class Meta: - tablename = "directors" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="directors", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="first_name") @@ -23,10 +24,11 @@ class Meta: class Movie(ormar.Model): - class Meta: - tablename = "movies" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="movies", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="title") @@ -50,9 +52,7 @@ async def test_updating_selected_columns(): director1 = await Director(name="Peter", last_name="Jackson").save() director2 = await Director(name="James", last_name="Cameron").save() - lotr = await Movie( - name="LOTR", year=2001, director=director1, profit=1.140 - ).save() + lotr = await Movie(name="LOTR", year=2001, director=director1, profit=1.140).save() lotr.name = "Lord of The Rings" lotr.year = 2003 @@ -84,9 +84,7 @@ async def test_updating_selected_columns(): async def test_not_passing_columns_or_empty_list_saves_all(): async with database: director = await Director(name="James", last_name="Cameron").save() - terminator = await Movie( - name="Terminator", year=1984, director=director, profit=0.078 - ).save() + terminator = await Movie(name="Terminator", year=1984, director=director, profit=0.078).save() terminator.name = "Terminator 2" terminator.year = 1991 diff --git a/tests/test_model_methods/test_upsert.py b/tests/test_model_methods/test_upsert.py index 178ae72e1..939c10df7 100644 --- a/tests/test_model_methods/test_upsert.py +++ b/tests/test_model_methods/test_upsert.py @@ -12,10 +12,11 @@ class Director(ormar.Model): - class Meta: - tablename = "directors" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="directors", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="first_name") @@ -23,10 +24,11 @@ class Meta: class Movie(ormar.Model): - class Meta: - tablename = "movies" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="movies", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="title") @@ -49,16 +51,14 @@ async def test_updating_selected_columns(): async with database: director1 = await Director(name="Peter", last_name="Jackson").save() - await Movie( - id=1, name="Lord of The Rings", year=2003, director=director1, profit=1.212 - ).upsert() + await Movie(id=1, name="Lord of The Rings", year=2003, director=director1, profit=1.212).upsert() with pytest.raises(ormar.NoMatch): await Movie.objects.get() - await Movie( - id=1, name="Lord of The Rings", year=2003, director=director1, profit=1.212 - ).upsert(__force_save__=True) + await Movie(id=1, name="Lord of The Rings", year=2003, director=director1, profit=1.212).upsert( + __force_save__=True + ) lotr = await Movie.objects.get() assert lotr.year == 2003 assert lotr.name == "Lord of The Rings" diff --git a/tests/test_queries/test_values_and_values_list.py b/tests/test_queries/test_values_and_values_list.py index fdad81b28..ff9f3712c 100644 --- a/tests/test_queries/test_values_and_values_list.py +++ b/tests/test_queries/test_values_and_values_list.py @@ -14,9 +14,10 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class User(ormar.Model): diff --git a/tests/test_relations/test_m2m_through_fields.py b/tests/test_relations/test_m2m_through_fields.py index 75f279e4f..c56b1ce3a 100644 --- a/tests/test_relations/test_m2m_through_fields.py +++ b/tests/test_relations/test_m2m_through_fields.py @@ -12,9 +12,10 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Category(ormar.Model): diff --git a/tests/test_relations/test_skipping_reverse.py b/tests/test_relations/test_skipping_reverse.py index 72a4861a2..bec61aa13 100644 --- a/tests/test_relations/test_skipping_reverse.py +++ b/tests/test_relations/test_skipping_reverse.py @@ -12,9 +12,10 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): From 7f351ecd7f75ac32b5869683ba7ee47fd50f3edc Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 13 Dec 2023 19:29:10 +0100 Subject: [PATCH 04/95] WIP - make whole test suit at least run - failing 49/443 tests --- benchmarks/conftest.py | 8 +- docs_src/aggregations/docs001.py | 8 +- docs_src/models/docs004.py | 2 +- docs_src/models/docs005.py | 2 +- examples/script_from_readme.py | 8 +- ormar/decorators/signals.py | 2 +- ormar/fields/foreign_key.py | 5 +- ormar/fields/many_to_many.py | 10 +- ormar/models/helpers/models.py | 2 +- ormar/models/helpers/pydantic.py | 4 +- ormar/models/helpers/sqlalchemy.py | 2 +- ormar/models/helpers/validation.py | 8 +- ormar/models/metaclass.py | 32 +-- ormar/models/mixins/prefetch_mixin.py | 14 +- ormar/models/mixins/pydantic_mixin.py | 59 ++--- ormar/models/newbasemodel.py | 1 + ormar/models/ormar_config.py | 5 +- ormar/models/quick_access_views.py | 1 + ormar/queryset/actions/select_action.py | 2 +- ormar/queryset/queries/prefetch_query.py | 10 +- ormar/queryset/reverse_alias_resolver.py | 4 +- ormar/relations/relation_manager.py | 2 +- .../test_deferred/test_forward_cross_refs.py | 26 +-- tests/test_deferred/test_forward_refs.py | 84 ++++--- .../test_more_same_table_joins.py | 45 ++-- tests/test_deferred/test_same_table_joins.py | 45 ++-- .../test_encryption/test_encrypted_columns.py | 38 ++- .../test_complex_relation_tree_performance.py | 107 +++------ .../test_dumping_model_to_dict.py | 32 +-- .../test_excludable_items.py | 21 +- .../test_excluding_fields_in_fastapi.py | 42 ++-- .../test_excluding_fields_with_default.py | 22 +- .../test_excluding_subset_of_columns.py | 20 +- .../test_pydantic_dict_params.py | 25 +- tests/test_fastapi/test_binary_fields.py | 11 +- tests/test_fastapi/test_choices_schema.py | 151 ------------ ...est_docs_with_multiple_relations_to_one.py | 17 +- tests/test_fastapi/test_enum_schema.py | 14 +- tests/test_fastapi/test_excluding_fields.py | 18 +- .../test_extra_ignore_parameter.py | 9 +- tests/test_fastapi/test_fastapi_docs.py | 33 +-- tests/test_fastapi/test_fastapi_usage.py | 18 +- tests/test_fastapi/test_json_field_fastapi.py | 14 +- tests/test_fastapi/test_m2m_forwardref.py | 10 +- .../test_more_reallife_fastapi.py | 18 +- tests/test_fastapi/test_nested_saving.py | 21 +- tests/test_fastapi/test_recursion_error.py | 27 ++- .../test_relations_with_nested_defaults.py | 20 +- .../test_schema_not_allowed_params.py | 11 +- .../test_fastapi/test_skip_reverse_models.py | 11 +- tests/test_fastapi/test_wekref_exclusion.py | 6 +- ...est_excluding_parent_fields_inheritance.py | 53 +++-- .../test_geting_pydantic_models.py | 30 +-- .../test_inheritance_concrete.py | 217 +++++++----------- .../test_inheritance_mixins.py | 67 +++--- .../test_inheritance_of_property_fields.py | 18 +- .../test_inheritance_with_default.py | 14 +- ...erited_class_is_not_abstract_by_default.py | 15 +- .../test_nested_models_pydantic.py | 20 +- .../test_pydantic_fields_order.py | 7 +- .../test_validators_are_inherited.py | 6 +- .../test_validators_in_generated_pydantic.py | 9 +- .../test_check_constraints.py | 12 +- .../test_index_constraints.py | 13 +- .../test_unique_constraints.py | 11 +- tests/test_model_methods/test_load_all.py | 15 +- .../test_ordering/test_default_model_order.py | 31 +-- .../test_default_relation_order.py | 39 ++-- .../test_default_through_relation_order.py | 67 ++---- .../test_proper_order_of_sorting_apply.py | 18 +- tests/test_queries/test_adding_related.py | 14 +- tests/test_queries/test_aggr_functions.py | 20 +- .../test_deep_relations_select_all.py | 90 ++++---- tests/test_queries/test_filter_groups.py | 14 +- .../test_indirect_relations_to_self.py | 18 +- tests/test_queries/test_isnull_filter.py | 25 +- .../test_nested_reverse_relations.py | 19 +- .../test_non_relation_fields_not_merged.py | 14 +- tests/test_queries/test_or_filters.py | 36 +-- tests/test_queries/test_order_by.py | 72 +++--- tests/test_queries/test_pagination.py | 17 +- .../test_queryproxy_on_m2m_models.py | 45 ++-- .../test_queryset_level_methods.py | 69 +++--- ...t_quoting_table_names_in_on_join_clause.py | 27 ++- .../test_reserved_sql_keywords_escaped.py | 14 +- .../test_queries/test_reverse_fk_queryset.py | 27 ++- .../test_selecting_subset_of_columns.py | 47 ++-- .../test_values_and_values_list.py | 12 +- tests/test_relations/test_cascades.py | 45 ++-- ...ustomizing_through_model_relation_names.py | 26 +-- .../test_database_fk_creation.py | 39 ++-- tests/test_relations/test_foreign_keys.py | 62 +++-- .../test_relations/test_m2m_through_fields.py | 27 +-- tests/test_relations/test_many_to_many.py | 33 +-- ...est_postgress_select_related_with_limit.py | 18 +- tests/test_relations/test_prefetch_related.py | 72 +++--- ...efetch_related_multiple_models_relation.py | 27 ++- .../test_python_style_relations.py | 29 +-- .../test_relations_default_exception.py | 36 +-- tests/test_relations/test_saving_related.py | 18 +- .../test_select_related_with_limit.py | 36 +-- ...select_related_with_m2m_and_pk_name_set.py | 22 +- .../test_selecting_proper_table_prefix.py | 27 ++- tests/test_relations/test_skipping_reverse.py | 11 +- .../test_through_relations_fail.py | 20 +- tests/test_relations/test_weakref_checking.py | 18 +- tests/test_signals/test_signals.py | 35 +-- .../test_signals_for_relations.py | 36 +-- tests/test_utils/test_queryset_utils.py | 9 +- 109 files changed, 1380 insertions(+), 1615 deletions(-) delete mode 100644 tests/test_fastapi/test_choices_schema.py diff --git a/benchmarks/conftest.py b/benchmarks/conftest.py index b5be8dad8..e14e65da3 100644 --- a/benchmarks/conftest.py +++ b/benchmarks/conftest.py @@ -20,10 +20,10 @@ pytestmark = pytest.mark.asyncio -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): class Meta(BaseMeta): diff --git a/docs_src/aggregations/docs001.py b/docs_src/aggregations/docs001.py index bc81e046c..843e010b6 100644 --- a/docs_src/aggregations/docs001.py +++ b/docs_src/aggregations/docs001.py @@ -10,10 +10,10 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): class Meta(BaseMeta): diff --git a/docs_src/models/docs004.py b/docs_src/models/docs004.py index cc8bce82a..0cac672be 100644 --- a/docs_src/models/docs004.py +++ b/docs_src/models/docs004.py @@ -17,7 +17,7 @@ class Meta(ormar.ModelMeta): # note you don't have to subclass - but it's recom completed: bool = ormar.Boolean(default=False) -print(Course.Meta.table.columns) +print(Course.ormar_config.table.columns) """ Will produce: ['courses.id', 'courses.name', 'courses.completed'] diff --git a/docs_src/models/docs005.py b/docs_src/models/docs005.py index 5359606ce..5190ea3f1 100644 --- a/docs_src/models/docs005.py +++ b/docs_src/models/docs005.py @@ -17,7 +17,7 @@ class Meta(ormar.ModelMeta): completed: bool = ormar.Boolean(default=False) -print({x: v.__dict__ for x, v in Course.Meta.model_fields.items()}) +print({x: v.__dict__ for x, v in Course.ormar_config.model_fields.items()}) """ Will produce: {'completed': mappingproxy({'autoincrement': False, diff --git a/examples/script_from_readme.py b/examples/script_from_readme.py index 95041c45b..0aff68222 100644 --- a/examples/script_from_readme.py +++ b/examples/script_from_readme.py @@ -14,10 +14,10 @@ # note that this step is optional -> all ormar cares is a internal # class with name Meta and proper parameters, but this way you do not # have to repeat the same parameters if you use only one database -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) # Note that all type hints are optional # below is a perfectly valid model declaration diff --git a/ormar/decorators/signals.py b/ormar/decorators/signals.py index 3e10c1dc2..3e328e51a 100644 --- a/ormar/decorators/signals.py +++ b/ormar/decorators/signals.py @@ -34,7 +34,7 @@ def _decorator(func: Callable) -> Callable: else: _senders = senders for sender in _senders: - signals = getattr(sender.Meta.signals, signal) + signals = getattr(sender.ormar_config.signals, signal) signals.connect(func) return func diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index c656862f5..6973fb84a 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -15,6 +15,7 @@ overload, ) +from pydantic.v1.typing import evaluate_forwardref import ormar # noqa I101 import sqlalchemy @@ -367,7 +368,9 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to.model_rebuild(force=True) + self.to = evaluate_forwardref( + self.to, globalns, localns or None # type: ignore + ) ( self.__type__, self.constraints, diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 30ff2c271..b22c683b0 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -12,6 +12,8 @@ overload, ) +from pydantic.v1.typing import evaluate_forwardref + import ormar # noqa: I100 from ormar import ModelDefinitionError from ormar.fields import BaseField @@ -222,14 +224,18 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to.model_rebuild(force=True) + self.to = evaluate_forwardref( + self.to, globalns, localns or None # type: ignore + ) (self.__type__, self.column_type) = populate_m2m_params_based_on_to_model( to=self.to, nullable=self.nullable ) if self.through.__class__ == ForwardRef: - self.through.model_rebuild(force=True) + self.through = evaluate_forwardref( + self.through, globalns, localns or None # type: ignore + ) forbid_through_relations(self.through) def get_relation_name(self) -> str: diff --git a/ormar/models/helpers/models.py b/ormar/models/helpers/models.py index 25e93158c..3a1858d11 100644 --- a/ormar/models/helpers/models.py +++ b/ormar/models/helpers/models.py @@ -97,7 +97,7 @@ def check_required_meta_parameters(new_model: Type["Model"]) -> None: raise ormar.ModelDefinitionError( f"{new_model.__name__} does not have database defined." ) - else: + elif not new_model.ormar_config.abstract: substitue_backend_pool_for_sqlite(new_model=new_model) if new_model.ormar_config.metadata is None and not new_model.ormar_config.abstract: diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index 725db1aa9..351af9926 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -163,6 +163,6 @@ def remove_excluded_parent_fields(model: Type["Model"]) -> None: *model.ormar_config.model_fields.keys() } if excludes: - model.__fields__ = { - k: v for k, v in model.__fields__.items() if k not in excludes + model.model_fields = { + k: v for k, v in model.model_fields.items() if k not in excludes } diff --git a/ormar/models/helpers/sqlalchemy.py b/ormar/models/helpers/sqlalchemy.py index c46223518..8dedcc127 100644 --- a/ormar/models/helpers/sqlalchemy.py +++ b/ormar/models/helpers/sqlalchemy.py @@ -291,7 +291,7 @@ def populate_meta_sqlalchemy_table_if_required(meta: "OrmarConfig") -> None: :param meta: Meta class of the Model without sqlalchemy table constructed :type meta: Model class Meta """ - if not meta.table and check_for_null_type_columns_from_forward_refs(meta): + if meta.table is None and check_for_null_type_columns_from_forward_refs(meta): set_constraint_names(meta=meta) table = sqlalchemy.Table( meta.tablename, meta.metadata, *meta.columns, *meta.constraints diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 5b2b91055..58faad02d 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -75,11 +75,11 @@ def generate_model_example(model: Type["Model"], relation_map: Dict = None) -> D if relation_map is not None else translate_list_to_dict(model._iterate_related_models()) ) - for name, field in model.Meta.model_fields.items(): + for name, field in model.ormar_config.model_fields.items(): populates_sample_fields_values( example=example, name=name, field=field, relation_map=relation_map ) - to_exclude = {name for name in model.Meta.model_fields} + to_exclude = {name for name in model.ormar_config.model_fields} pydantic_repr = generate_pydantic_example(pydantic_model=model, exclude=to_exclude) example.update(pydantic_repr) @@ -204,7 +204,7 @@ def overwrite_binary_format(schema: Dict[str, Any], model: Type["Model"]) -> Non for field_id, prop in schema.get("properties", {}).items(): if ( field_id in model._bytes_fields - and model.Meta.model_fields[field_id].represent_as_base64_str + and model.ormar_config.model_fields[field_id].represent_as_base64_str ): prop["format"] = "base64" if prop.get("enum"): @@ -231,7 +231,7 @@ def construct_modify_schema_function(fields_with_choices: List) -> Callable: def schema_extra(schema: Dict[str, Any], model: Type["Model"]) -> None: for field_id, prop in schema.get("properties", {}).items(): if field_id in fields_with_choices: - prop["enum"] = list(model.Meta.model_fields[field_id].choices) + prop["enum"] = list(model.ormar_config.model_fields[field_id].choices) prop["description"] = prop.get("description", "") + "An enumeration." overwrite_example_and_description(schema=schema, model=model) overwrite_binary_format(schema=schema, model=model) diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 20d63c067..7410d6844 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -187,7 +187,7 @@ def verify_constraint_names( :type parent_value: List """ new_aliases = {x.name: x.get_alias() for x in model_fields.values()} - old_aliases = {x.name: x.get_alias() for x in base_class.Meta.model_fields.values()} + old_aliases = {x.name: x.get_alias() for x in base_class.ormar_config.model_fields.values()} old_aliases.update(new_aliases) constraints_columns = [x._pending_colargs for x in parent_value] for column_set in constraints_columns: @@ -245,9 +245,9 @@ def update_attrs_from_base_meta( # noqa: CCR001 params_to_update = ["metadata", "database", "constraints", "property_fields"] for param in params_to_update: - current_value = attrs.get("Meta", {}).__dict__.get(param, ormar.Undefined) + current_value = attrs.get("ormar_config", {}).__dict__.get(param, ormar.Undefined) parent_value = ( - base_class.Meta.__dict__.get(param) if hasattr(base_class, "Meta") else None + base_class.ormar_config.__dict__.get(param) if hasattr(base_class, "ormar_config") else None ) if parent_value: if param == "constraints": @@ -260,7 +260,7 @@ def update_attrs_from_base_meta( # noqa: CCR001 if isinstance(current_value, list): current_value.extend(parent_value) else: - setattr(attrs["Meta"], param, parent_value) + setattr(attrs["ormar_config"], param, parent_value) def copy_and_replace_m2m_through_model( # noqa: CFQ002 @@ -311,16 +311,16 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 field.owner = base_class field.create_default_through_model() through_class = field.through - new_meta: ormar.ModelMeta = type( # type: ignore - "Meta", (), dict(through_class.Meta.__dict__) - ) + # TODO: CHECK PKNAME + new_meta = ormar.OrmarConfig() + new_meta.__dict__ = through_class.ormar_config.__dict__.copy() copy_name = through_class.__name__ + attrs.get("__name__", "") - copy_through = type(copy_name, (ormar.Model,), {"Meta": new_meta}) + copy_through = type(copy_name, (ormar.Model,), {"ormar_config": new_meta}) new_meta.tablename += "_" + meta.tablename # create new table with copied columns but remove foreign keys # they will be populated later in expanding reverse relation if hasattr(new_meta, "table"): - del new_meta.table + new_meta.table = None new_meta.model_fields = { name: field for name, field in new_meta.model_fields.items() @@ -335,8 +335,8 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 parent_fields[field_name] = copy_field - if through_class.Meta.table in through_class.Meta.metadata: - through_class.Meta.metadata.remove(through_class.Meta.table) + if through_class.ormar_config.table in through_class.ormar_config.metadata: + through_class.ormar_config.metadata.remove(through_class.ormar_config.table) def copy_data_from_parent_model( # noqa: CCR001 @@ -366,8 +366,8 @@ def copy_data_from_parent_model( # noqa: CCR001 :return: updated attrs and model_fields :rtype: Tuple[Dict, Dict] """ - if attrs.get("Meta"): - if model_fields and not base_class.Meta.abstract: # type: ignore + if attrs.get("ormar_config"): + if model_fields and not base_class.ormar_config.abstract: # type: ignore raise ModelDefinitionError( f"{curr_class.__name__} cannot inherit " f"from non abstract class {base_class.__name__}" @@ -378,7 +378,7 @@ def copy_data_from_parent_model( # noqa: CCR001 model_fields=model_fields, ) parent_fields: Dict = dict() - meta = attrs.get("Meta") + meta = attrs.get("ormar_config") if not meta: # pragma: no cover raise ModelDefinitionError( f"Model {curr_class.__name__} declared without Meta" @@ -388,7 +388,7 @@ def copy_data_from_parent_model( # noqa: CCR001 if hasattr(meta, "tablename") and meta.tablename else attrs.get("__name__", "").lower() + "s" ) - for field_name, field in base_class.Meta.model_fields.items(): + for field_name, field in base_class.ormar_config.model_fields.items(): if ( hasattr(meta, "exclude_parent_fields") and field_name in meta.exclude_parent_fields @@ -508,7 +508,7 @@ def update_attrs_and_fields( ) -> Dict: """ Updates __annotations__, values of model fields (so pydantic FieldInfos) - as well as model.Meta.model_fields definitions from parents. + as well as model.ormar_config.model_fields definitions from parents. :param attrs: new namespace for class being constructed :type attrs: Dict diff --git a/ormar/models/mixins/prefetch_mixin.py b/ormar/models/mixins/prefetch_mixin.py index 9f945cb4a..b9a9aec72 100644 --- a/ormar/models/mixins/prefetch_mixin.py +++ b/ormar/models/mixins/prefetch_mixin.py @@ -38,15 +38,15 @@ def get_clause_target_and_filter_column_name( :rtype: Tuple[Type[Model], str] """ if reverse: - field_name = parent_model.Meta.model_fields[related].get_related_name() - field = target_model.Meta.model_fields[field_name] + field_name = parent_model.ormar_config.model_fields[related].get_related_name() + field = target_model.ormar_config.model_fields[field_name] if field.is_multi: field = cast("ManyToManyField", field) field_name = field.default_target_field_name() - sub_field = field.through.Meta.model_fields[field_name] + sub_field = field.through.ormar_config.model_fields[field_name] return field.through, sub_field.get_alias() return target_model, field.get_alias() - target_field = target_model.get_column_alias(target_model.Meta.pkname) + target_field = target_model.get_column_alias(target_model.ormar_config.pkname) return target_model, target_field @staticmethod @@ -70,11 +70,11 @@ def get_column_name_for_id_extraction( :rtype: """ if reverse: - column_name = parent_model.Meta.pkname + column_name = parent_model.ormar_config.pkname return ( parent_model.get_column_alias(column_name) if use_raw else column_name ) - column = parent_model.Meta.model_fields[related] + column = parent_model.ormar_config.model_fields[related] return column.get_alias() if use_raw else column.name @classmethod @@ -93,7 +93,7 @@ def get_related_field_name(cls, target_field: "ForeignKeyField") -> str: return cls.get_name() if target_field.virtual: return target_field.get_related_name() - return target_field.to.Meta.pkname + return target_field.to.ormar_config.pkname @classmethod def get_filtered_names_to_extract(cls, prefetch_dict: Dict) -> List: diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index c4ee21a04..995aaa673 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -26,7 +26,7 @@ class PydanticMixin(RelationMixin): __cache__: Dict[str, Type[pydantic.BaseModel]] = {} if TYPE_CHECKING: # pragma: no cover - __fields__: Dict[str, Field] + model_fields: Dict[str, Field] _skip_ellipsis: Callable _get_not_excluded_fields: Callable @@ -66,10 +66,10 @@ def _convert_ormar_to_pydantic( fields_dict: Dict[str, Any] = dict() defaults: Dict[str, Any] = dict() fields_to_process = cls._get_not_excluded_fields( - fields={*cls.Meta.model_fields.keys()}, include=include, exclude=exclude + fields={*cls.ormar_config.model_fields.keys()}, include=include, exclude=exclude ) fields_to_process.sort( - key=lambda x: list(cls.Meta.model_fields.keys()).index(x) + key=lambda x: list(cls.ormar_config.model_fields.keys()).index(x) ) cache_key = f"{cls.__name__}_{str(include)}_{str(exclude)}" @@ -105,7 +105,7 @@ def _determine_pydantic_field_type( exclude: Union[Set, Dict, None], relation_map: Dict[str, Any], ) -> Any: - field = cls.Meta.model_fields[name] + field = cls.ormar_config.model_fields[name] target: Any = None if field.is_relation and name in relation_map: # type: ignore target = field.to._convert_ormar_to_pydantic( @@ -118,7 +118,7 @@ def _determine_pydantic_field_type( if field.is_multi or field.virtual: target = List[target] # type: ignore elif not field.is_relation: - defaults[name] = cls.__fields__[name].field_info + defaults[name] = cls.model_fields[name].default target = field.__type__ if target is not None and field.nullable: target = Optional[target] @@ -129,27 +129,28 @@ def _copy_field_validators(cls, model: Type[pydantic.BaseModel]) -> None: """ Copy field validators from ormar model to generated pydantic model. """ - for field_name, field in model.__fields__.items(): - if ( - field_name not in cls.__fields__ - or cls.Meta.model_fields[field_name].is_relation - ): - continue - validators = cls.__fields__[field_name].validators - already_attached = [ - validator.__wrapped__ for validator in field.validators # type: ignore - ] - validators_to_copy = [ - validator - for validator in validators - if validator.__wrapped__ not in already_attached # type: ignore - ] - field.validators.extend(copy.deepcopy(validators_to_copy)) - class_validators = cls.__fields__[field_name].class_validators - field.class_validators.update(copy.deepcopy(class_validators)) - field.pre_validators = copy.deepcopy( - cls.__fields__[field_name].pre_validators - ) - field.post_validators = copy.deepcopy( - cls.__fields__[field_name].post_validators - ) + # TODO: FIX THIS + # for field_name, field in model.model_fields.items(): + # if ( + # field_name not in cls.model_fields + # or cls.ormar_config.model_fields[field_name].is_relation + # ): + # continue + # validators = cls.model_fields[field_name].validators + # already_attached = [ + # validator.__wrapped__ for validator in field.validators # type: ignore + # ] + # validators_to_copy = [ + # validator + # for validator in validators + # if validator.__wrapped__ not in already_attached # type: ignore + # ] + # field.validators.extend(copy.deepcopy(validators_to_copy)) + # class_validators = cls.model_fields[field_name].class_validators + # field.class_validators.update(copy.deepcopy(class_validators)) + # field.pre_validators = copy.deepcopy( + # cls.model_fields[field_name].pre_validators + # ) + # field.post_validators = copy.deepcopy( + # cls.model_fields[field_name].post_validators + # ) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 4193d2d15..e8e6855db 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -203,6 +203,7 @@ def __getattr__(self, item: str) -> Any: :return: Any :rtype: Any """ + # TODO: To many fields land here - descriptors problem? return super().__getattr__(item) def __getstate__(self) -> Dict[Any, Any]: diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index efa0d94d2..ab6bed4a2 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -23,6 +23,7 @@ def __init__( exclude_parent_fields: Optional[List[str]] = None, queryset_class: Type[QuerySet] = QuerySet, extra: Extra = Extra.forbid, + constraints: Optional[List[ColumnCollectionConstraint]] = None, ) -> None: self.pkname: str = None self.metadata = metadata @@ -30,7 +31,7 @@ def __init__( self.tablename = tablename self.orders_by = order_by or [] self.columns: List[sqlalchemy.Column] = [] - self.constraints: List[ColumnCollectionConstraint] = [] + self.constraints= constraints or [] self.model_fields: Dict[ str, Union[BaseField, ForeignKeyField, ManyToManyField] ] = {} @@ -54,6 +55,7 @@ def copy( exclude_parent_fields: Optional[List[str]] = None, queryset_class: Optional[Type[QuerySet]] = None, extra: Optional[Extra] = None, + constraints: Optional[List[ColumnCollectionConstraint]] = None, ) -> "OrmarConfig": return OrmarConfig( metadata=metadata or self.metadata, @@ -64,4 +66,5 @@ def copy( exclude_parent_fields=exclude_parent_fields, queryset_class=queryset_class or self.queryset_class, extra=extra or self.extra, + constraints=constraints ) diff --git a/ormar/models/quick_access_views.py b/ormar/models/quick_access_views.py index 0949c1baf..318c38e9d 100644 --- a/ormar/models/quick_access_views.py +++ b/ormar/models/quick_access_views.py @@ -5,6 +5,7 @@ quick_access_set = { "Config", "model_config", + "__cached_hash__", "__class__", "__config__", "__custom_root_type__", diff --git a/ormar/queryset/actions/select_action.py b/ormar/queryset/actions/select_action.py index 92e59916e..c18e6f6db 100644 --- a/ormar/queryset/actions/select_action.py +++ b/ormar/queryset/actions/select_action.py @@ -36,7 +36,7 @@ def is_numeric(self) -> bool: return self.get_target_field_type() in [int, float, decimal.Decimal] def get_target_field_type(self) -> Any: - return self.target_model.Meta.model_fields[self.field_name].__type__ + return self.target_model.ormar_config.model_fields[self.field_name].__type__ def get_text_clause(self) -> sqlalchemy.sql.expression.TextClause: alias = f"{self.table_prefix}_" if self.table_prefix else "" diff --git a/ormar/queryset/queries/prefetch_query.py b/ormar/queryset/queries/prefetch_query.py index d30b9d77e..3413bc4f5 100644 --- a/ormar/queryset/queries/prefetch_query.py +++ b/ormar/queryset/queries/prefetch_query.py @@ -98,7 +98,7 @@ def __init__( # noqa: CFQ002 ) -> None: self.model = model_cls - self.database = self.model.Meta.database + self.database = self.model.ormar_config.database self._prefetch_related = prefetch_related self._select_related = select_related self.excludable = excludable @@ -279,7 +279,7 @@ def _populate_nested_related( ) for related in related_to_extract: - target_field = model.Meta.model_fields[related] + target_field = model.ormar_config.model_fields[related] target_field = cast("ForeignKeyField", target_field) target_model = target_field.to.get_name() model_id = model.get_relation_model_id(target_field=target_field) @@ -381,7 +381,7 @@ async def _extract_related_models( # noqa: CFQ002, CCR001 :return: None :rtype: None """ - target_field = target_model.Meta.model_fields[related] + target_field = target_model.ormar_config.model_fields[related] target_field = cast("ForeignKeyField", target_field) reverse = False if target_field.virtual or target_field.is_multi: @@ -473,13 +473,13 @@ async def _run_prefetch_query( select_related = [] query_target = target_model table_prefix = "" - exclude_prefix = target_field.to.Meta.alias_manager.resolve_relation_alias( + exclude_prefix = target_field.to.ormar_config.alias_manager.resolve_relation_alias( from_model=target_field.owner, relation_name=target_field.name ) if target_field.is_multi: query_target = target_field.through select_related = [target_name] - table_prefix = target_field.to.Meta.alias_manager.resolve_relation_alias( + table_prefix = target_field.to.ormar_config.alias_manager.resolve_relation_alias( from_model=query_target, relation_name=target_name ) exclude_prefix = table_prefix diff --git a/ormar/queryset/reverse_alias_resolver.py b/ormar/queryset/reverse_alias_resolver.py index b9ed1c862..19a41a5b7 100644 --- a/ormar/queryset/reverse_alias_resolver.py +++ b/ormar/queryset/reverse_alias_resolver.py @@ -20,7 +20,7 @@ def __init__( ) -> None: self.select_related = select_related self.model_cls = model_cls - self.reversed_aliases = self.model_cls.Meta.alias_manager.reversed_aliases + self.reversed_aliases = self.model_cls.ormar_config.alias_manager.reversed_aliases self.excludable = excludable self.exclude_through = exclude_through @@ -176,7 +176,7 @@ def _create_prefixes_map(self) -> None: for relation in related_split: previous_related_str = f"{related_str}__" if related_str else "" new_related_str = previous_related_str + relation - field = model_cls.Meta.model_fields[relation] + field = model_cls.ormar_config.model_fields[relation] field = cast("ForeignKeyField", field) prefix_name = self._handle_through_fields_and_prefix( model_cls=model_cls, diff --git a/ormar/relations/relation_manager.py b/ormar/relations/relation_manager.py index e188bdabb..ce47fe5e4 100644 --- a/ormar/relations/relation_manager.py +++ b/ormar/relations/relation_manager.py @@ -120,7 +120,7 @@ def remove_parent( :param name: name of the relation :type name: str """ - relation_name = item.Meta.model_fields[name].get_related_name() + relation_name = item.ormar_config.model_fields[name].get_related_name() item._orm.remove(name, parent) parent._orm.remove(relation_name, item) diff --git a/tests/test_deferred/test_forward_cross_refs.py b/tests/test_deferred/test_forward_cross_refs.py index 580575929..43399517a 100644 --- a/tests/test_deferred/test_forward_cross_refs.py +++ b/tests/test_deferred/test_forward_cross_refs.py @@ -4,7 +4,7 @@ import databases import pytest import sqlalchemy as sa -from pydantic.typing import ForwardRef +from typing import ForwardRef from sqlalchemy import create_engine import ormar @@ -18,14 +18,14 @@ TeacherRef = ForwardRef("Teacher") -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = db +base_ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, +) class Student(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -35,14 +35,10 @@ class Meta(BaseMeta): class StudentTeacher(ormar.Model): - class Meta(BaseMeta): - tablename = "students_x_teachers" - + ormar_config = base_ormar_config.copy(tablename = "students_x_teachers") class Teacher(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -58,8 +54,7 @@ class Meta(ModelMeta): class Country(ormar.Model): - class Meta(BaseMeta): - tablename = "countries" + ormar_config = base_ormar_config.copy(tablename = "countries") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128) @@ -70,8 +65,7 @@ class Meta(BaseMeta): class City(ormar.Model): - class Meta(BaseMeta): - tablename = "cities" + ormar_config = base_ormar_config.copy(tablename = "cities") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128) diff --git a/tests/test_deferred/test_forward_refs.py b/tests/test_deferred/test_forward_refs.py index 275311375..628755446 100644 --- a/tests/test_deferred/test_forward_refs.py +++ b/tests/test_deferred/test_forward_refs.py @@ -5,7 +5,7 @@ import pytest import pytest_asyncio import sqlalchemy as sa -from pydantic.typing import ForwardRef +from typing import ForwardRef from sqlalchemy import create_engine import ormar @@ -21,9 +21,10 @@ class Person(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -38,9 +39,10 @@ class Meta(ModelMeta): class Child(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -54,15 +56,17 @@ class Meta(ModelMeta): class ChildFriend(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) class Game(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -93,9 +97,10 @@ async def test_not_updated_model_raises_errors(): Person2Ref = ForwardRef("Person2") class Person2(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -116,14 +121,16 @@ async def test_not_updated_model_m2m_raises_errors(): Person3Ref = ForwardRef("Person3") class PersonFriend(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) class Person3(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -146,17 +153,19 @@ async def test_not_updated_model_m2m_through_raises_errors(): PersonPetRef = ForwardRef("PersonPet") class Pet(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + 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 + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -165,9 +174,10 @@ class Meta(ModelMeta): ) class PersonPet(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + ) with pytest.raises(ModelError): await Person4.objects.create(name="Test") @@ -180,19 +190,19 @@ class Meta(ModelMeta): def test_proper_field_init(): - assert "supervisor" in Person.Meta.model_fields - assert Person.Meta.model_fields["supervisor"].to == Person + assert "supervisor" in Person.ormar_config.model_fields + assert Person.ormar_config.model_fields["supervisor"].to == Person assert "supervisor" in Person.__fields__ assert Person.__fields__["supervisor"].type_ == Person - assert "supervisor" in Person.Meta.table.columns + assert "supervisor" in Person.ormar_config.table.columns assert isinstance( - Person.Meta.table.columns["supervisor"].type, sa.sql.sqltypes.Integer + Person.ormar_config.table.columns["supervisor"].type, sa.sql.sqltypes.Integer ) - assert len(Person.Meta.table.columns["supervisor"].foreign_keys) > 0 + assert len(Person.ormar_config.table.columns["supervisor"].foreign_keys) > 0 - assert "person_supervisor" in Person.Meta.alias_manager._aliases_new + assert "person_supervisor" in Person.ormar_config.alias_manager._aliases_new @pytest.mark.asyncio diff --git a/tests/test_deferred/test_more_same_table_joins.py b/tests/test_deferred/test_more_same_table_joins.py index c4f906be4..f06d28e28 100644 --- a/tests/test_deferred/test_more_same_table_joins.py +++ b/tests/test_deferred/test_more_same_table_joins.py @@ -13,30 +13,33 @@ class Department(ormar.Model): - class Meta: - tablename = "departments" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "departments", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True, autoincrement=False) name: str = ormar.String(max_length=100) class SchoolClass(ormar.Model): - class Meta: - tablename = "schoolclasses" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "schoolclasses", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "categories", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -44,10 +47,11 @@ class Meta: class Student(ormar.Model): - class Meta: - tablename = "students" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "students", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -56,10 +60,11 @@ class Meta: class Teacher(ormar.Model): - class Meta: - tablename = "teachers" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "teachers", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_deferred/test_same_table_joins.py b/tests/test_deferred/test_same_table_joins.py index dd03e8dab..c6e138e45 100644 --- a/tests/test_deferred/test_same_table_joins.py +++ b/tests/test_deferred/test_same_table_joins.py @@ -13,20 +13,22 @@ class Department(ormar.Model): - class Meta: - tablename = "departments" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "departments", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True, autoincrement=False) name: str = ormar.String(max_length=100) class SchoolClass(ormar.Model): - class Meta: - tablename = "schoolclasses" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "schoolclasses", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -34,20 +36,22 @@ class Meta: class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "categories", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Student(ormar.Model): - class Meta: - tablename = "students" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "students", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -56,10 +60,11 @@ class Meta: class Teacher(ormar.Model): - class Meta: - tablename = "teachers" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "teachers", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_encryption/test_encrypted_columns.py b/tests/test_encryption/test_encrypted_columns.py index 387d84eae..c63d920c4 100644 --- a/tests/test_encryption/test_encrypted_columns.py +++ b/tests/test_encryption/test_encrypted_columns.py @@ -19,15 +19,13 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - - -default_fernet = dict( - encrypt_secret="asd123", encrypt_backend=ormar.EncryptBackends.FERNET +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, ) +default_fernet = dict(encrypt_secret="asd123", encrypt_backend=ormar.EncryptBackends.FERNET) + class DummyBackend(ormar.fields.EncryptBackend): def _initialize_backend(self, secret_key: bytes) -> None: @@ -41,8 +39,7 @@ def decrypt(self, value: Any) -> str: class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, **default_fernet) @@ -79,8 +76,7 @@ class Meta(BaseMeta): class Hash(ormar.Model): - class Meta(BaseMeta): - tablename = "hashes" + ormar_config = base_ormar_config.copy(tablename="hashes") id: int = ormar.Integer(primary_key=True) name: str = ormar.String( @@ -91,8 +87,7 @@ class Meta(BaseMeta): class Filter(ormar.Model): - class Meta(BaseMeta): - tablename = "filters" + ormar_config = base_ormar_config.copy(tablename="filters") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, **default_fernet) @@ -100,8 +95,7 @@ class Meta(BaseMeta): class Report(ormar.Model): - class Meta(BaseMeta): - tablename = "reports" + ormar_config = base_ormar_config.copy(tablename="reports") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -121,8 +115,7 @@ def test_error_on_encrypted_pk(): with pytest.raises(ModelDefinitionError): class Wrong(ormar.Model): - class Meta(BaseMeta): - tablename = "wrongs" + ormar_config = base_ormar_config.copy(tablename="wrongs") id: int = ormar.Integer( primary_key=True, @@ -135,8 +128,7 @@ def test_error_on_encrypted_relation(): with pytest.raises(ModelDefinitionError): class Wrong2(ormar.Model): - class Meta(BaseMeta): - tablename = "wrongs2" + ormar_config = base_ormar_config.copy(tablename="wrongs2") id: int = ormar.Integer(primary_key=True) author = ormar.ForeignKey( @@ -150,8 +142,7 @@ def test_error_on_encrypted_m2m_relation(): with pytest.raises(ModelDefinitionError): class Wrong3(ormar.Model): - class Meta(BaseMeta): - tablename = "wrongs3" + ormar_config = base_ormar_config.copy(tablename="wrongs3") id: int = ormar.Integer(primary_key=True) author = ormar.ManyToMany( @@ -165,8 +156,7 @@ def test_wrong_backend(): with pytest.raises(ModelDefinitionError): class Wrong3(ormar.Model): - class Meta(BaseMeta): - tablename = "wrongs3" + ormar_config = base_ormar_config.copy(tablename="wrongs3") id: int = ormar.Integer(primary_key=True) author = ormar.Integer( @@ -177,7 +167,7 @@ class Meta(BaseMeta): def test_db_structure(): - assert Author.Meta.table.c.get("name").type.__class__ == EncryptedString + assert Author.ormar_config.table.c.get("name").type.__class__ == EncryptedString @pytest.mark.asyncio diff --git a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py index 561893cf5..86439203d 100644 --- a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py +++ b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py @@ -14,101 +14,89 @@ metadata = sqlalchemy.MetaData() -class MainMeta(orm.ModelMeta): - database = database - metadata = metadata +base_ormar_config = orm.OrmarConfig( + database=database, + metadata=metadata, +) class ChagenlogRelease(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "changelog_release" + ormar_config = base_ormar_config.copy(tablename="changelog_release") class CommitIssue(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "commit_issues" + ormar_config = base_ormar_config.copy(tablename="commit_issues") class CommitLabel(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "commit_label" + ormar_config = base_ormar_config.copy(tablename="commit_label") class MergeRequestCommit(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "merge_request_commits" + ormar_config = base_ormar_config.copy(tablename="merge_request_commits") class MergeRequestIssue(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "merge_request_issues" + ormar_config = base_ormar_config.copy(tablename="merge_request_issues") class MergeRequestLabel(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "merge_request_labels" + ormar_config = base_ormar_config.copy(tablename="merge_request_labels") class ProjectLabel(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "project_label" + ormar_config = base_ormar_config.copy(tablename="project_label") class PushCommit(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "push_commit" + ormar_config = base_ormar_config.copy(tablename="push_commit") class PushLabel(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "push_label" + ormar_config = base_ormar_config.copy(tablename="push_label") class TagCommit(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "tag_commits" + ormar_config = base_ormar_config.copy(tablename="tag_commits") class TagIssue(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "tag_issue" + ormar_config = base_ormar_config.copy(tablename="tag_issue") class TagLabel(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - class Meta(MainMeta): - tablename = "tag_label" + ormar_config = base_ormar_config.copy(tablename="tag_label") class UserProject(orm.Model): id: int = orm.Integer(name="id", primary_key=True) access_level: int = orm.Integer(default=0) - class Meta(MainMeta): - tablename = "user_project" + ormar_config = base_ormar_config.copy(tablename="user_project") class Label(orm.Model): @@ -117,8 +105,7 @@ class Label(orm.Model): description: str = orm.Text(default="") type: str = orm.String(max_length=100, default="") - class Meta(MainMeta): - tablename = "labels" + ormar_config = base_ormar_config.copy(tablename="labels") class Project(orm.Model): @@ -139,8 +126,7 @@ class Project(orm.Model): changelog_file: str = orm.String(max_length=250, default="") version_file: str = orm.String(max_length=250, default="") - class Meta(MainMeta): - tablename = "projects" + ormar_config = base_ormar_config.copy(tablename="projects") class Issue(orm.Model): @@ -154,8 +140,7 @@ class Issue(orm.Model): change_type: str = orm.String(max_length=100, default="") data: pydantic.Json = orm.JSON(default={}) - class Meta(MainMeta): - tablename = "issues" + ormar_config = base_ormar_config.copy(tablename="issues") class User(orm.Model): @@ -163,8 +148,7 @@ class User(orm.Model): username: str = orm.String(max_length=100, unique=True) name: str = orm.String(max_length=200, default="") - class Meta(MainMeta): - tablename = "users" + ormar_config = base_ormar_config.copy(tablename="users") class Branch(orm.Model): @@ -177,8 +161,7 @@ class Branch(orm.Model): postfix_tag: str = orm.String(max_length=50, default="") project: Project = orm.ForeignKey(Project, ondelete="CASCADE", onupdate="CASCADE") - class Meta(MainMeta): - tablename = "branches" + ormar_config = base_ormar_config.copy(tablename="branches") class Changelog(orm.Model): @@ -186,14 +169,11 @@ class Changelog(orm.Model): content: str = orm.Text(default="") version: str = orm.Text(default="") past_changelog: int = orm.Integer(default=0) - label: Label = orm.ForeignKey( - Label, nullable=True, ondelete="CASCADE", onupdate="CASCADE" - ) + label: Label = orm.ForeignKey(Label, nullable=True, ondelete="CASCADE", onupdate="CASCADE") project: Project = orm.ForeignKey(Project, ondelete="CASCADE", onupdate="CASCADE") created_date: datetime = orm.DateTime(default=datetime.utcnow()) - class Meta(MainMeta): - tablename = "changelogs" + ormar_config = base_ormar_config.copy(tablename="changelogs") class Commit(orm.Model): @@ -210,8 +190,7 @@ class Commit(orm.Model): Issue, through=CommitIssue, ondelete="CASCADE", onupdate="CASCADE" ) - class Meta(MainMeta): - tablename = "commits" + ormar_config = base_ormar_config.copy(tablename="commits") class MergeRequest(orm.Model): @@ -234,15 +213,12 @@ class MergeRequest(orm.Model): ) project: Project = orm.ForeignKey(Project, ondelete="CASCADE", onupdate="CASCADE") - class Meta(MainMeta): - tablename = "merge_requests" + ormar_config = base_ormar_config.copy(tablename="merge_requests") class Push(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - branch: Branch = orm.ForeignKey( - Branch, nullable=True, ondelete="CASCADE", onupdate="CASCADE" - ) + branch: Branch = orm.ForeignKey(Branch, nullable=True, ondelete="CASCADE", onupdate="CASCADE") has_locking_changes: bool = orm.Boolean(default=False) sha: str = orm.String(max_length=200) labels: Optional[Union[List[Label], Label]] = orm.ManyToMany( @@ -259,8 +235,7 @@ class Push(orm.Model): author: User = orm.ForeignKey(User, ondelete="CASCADE", onupdate="CASCADE") project: Project = orm.ForeignKey(Project, ondelete="CASCADE", onupdate="CASCADE") - class Meta(MainMeta): - tablename = "pushes" + ormar_config = base_ormar_config.copy(tablename="pushes") class Tag(orm.Model): @@ -284,15 +259,10 @@ class Tag(orm.Model): labels: Optional[Union[List[Label], Label]] = orm.ManyToMany( Label, through=TagLabel, ondelete="CASCADE", onupdate="CASCADE" ) - user: User = orm.ForeignKey( - User, nullable=True, ondelete="CASCADE", onupdate="CASCADE" - ) - branch: Branch = orm.ForeignKey( - Branch, nullable=True, ondelete="CASCADE", onupdate="CASCADE" - ) + user: User = orm.ForeignKey(User, nullable=True, ondelete="CASCADE", onupdate="CASCADE") + branch: Branch = orm.ForeignKey(Branch, nullable=True, ondelete="CASCADE", onupdate="CASCADE") - class Meta(MainMeta): - tablename = "tags" + ormar_config = base_ormar_config.copy(tablename="tags") class Release(orm.Model): @@ -305,23 +275,16 @@ class Release(orm.Model): ) data: pydantic.Json = orm.JSON(default={}) - class Meta(MainMeta): - tablename = "releases" + ormar_config = base_ormar_config.copy(tablename="releases") class Webhook(orm.Model): id: int = orm.Integer(name="id", primary_key=True) object_kind = orm.String(max_length=100) project: Project = orm.ForeignKey(Project, ondelete="CASCADE", onupdate="CASCADE") - merge_request: MergeRequest = orm.ForeignKey( - MergeRequest, nullable=True, ondelete="CASCADE", onupdate="CASCADE" - ) - tag: Tag = orm.ForeignKey( - Tag, nullable=True, ondelete="CASCADE", onupdate="CASCADE" - ) - push: Push = orm.ForeignKey( - Push, nullable=True, ondelete="CASCADE", onupdate="CASCADE" - ) + merge_request: MergeRequest = orm.ForeignKey(MergeRequest, nullable=True, ondelete="CASCADE", onupdate="CASCADE") + tag: Tag = orm.ForeignKey(Tag, nullable=True, ondelete="CASCADE", onupdate="CASCADE") + push: Push = orm.ForeignKey(Push, nullable=True, ondelete="CASCADE", onupdate="CASCADE") created_at: datetime = orm.DateTime(default=datetime.now()) data: pydantic.Json = orm.JSON(default={}) status: int = orm.Integer(default=200) diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index 8b89e213a..c5fc65b84 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -11,22 +11,21 @@ database = databases.Database(DATABASE_URL, force_rollback=True) -class MainMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Role(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, nullable=False) class User(ormar.Model): - class Meta(MainMeta): - tablename: str = "users" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255, nullable=False) @@ -36,20 +35,14 @@ class Meta(MainMeta): class Tier(ormar.Model): - class Meta: - tablename = "tiers" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -57,10 +50,7 @@ class Meta: class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -141,9 +131,7 @@ def test_dumping_to_dict_exclude_nested_dict(sample_data): def test_dumping_to_dict_exclude_and_include_nested_dict(sample_data): item1, item2 = sample_data - dict1 = item2.dict( - exclude={"category": {"tier": {"name"}}}, include={"name", "category"} - ) + dict1 = item2.dict(exclude={"category": {"tier": {"name"}}}, include={"name", "category"}) assert dict1.get("name") == "M16" assert "category" in dict1 assert dict1["category"]["name"] == "Weapons" diff --git a/tests/test_exclude_include_dict/test_excludable_items.py b/tests/test_exclude_include_dict/test_excludable_items.py index c59b9154a..37cf0be0b 100644 --- a/tests/test_exclude_include_dict/test_excludable_items.py +++ b/tests/test_exclude_include_dict/test_excludable_items.py @@ -18,8 +18,7 @@ class NickNames(ormar.Model): - class Meta(BaseMeta): - tablename = "nicks" + ormar_config = base_ormar_config.copy(tablename="nicks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -27,13 +26,11 @@ class Meta(BaseMeta): class NicksHq(ormar.Model): - class Meta(BaseMeta): - tablename = "nicks_x_hq" + ormar_config = base_ormar_config.copy(tablename="nicks_x_hq") class HQ(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -41,8 +38,7 @@ class Meta(BaseMeta): class Company(ormar.Model): - class Meta(BaseMeta): - tablename = "companies" + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -51,8 +47,7 @@ class Meta(BaseMeta): class Car(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) manufacturer: Optional[Company] = ormar.ForeignKey(Company) @@ -70,7 +65,7 @@ def compare_results(excludable): assert car_excludable.is_excluded("year") - alias = Company.Meta.alias_manager.resolve_relation_alias(Car, "manufacturer") + alias = Company.ormar_config.alias_manager.resolve_relation_alias(Car, "manufacturer") manu_excludable = excludable.get(Company, alias=alias) assert manu_excludable.exclude == {"founded"} assert manu_excludable.include == set() @@ -79,7 +74,7 @@ def compare_results(excludable): def compare_results_include(excludable): - manager = Company.Meta.alias_manager + manager = Company.ormar_config.alias_manager car_excludable = excludable.get(Car) assert car_excludable.include == {"id", "name"} assert car_excludable.exclude == set() @@ -205,7 +200,7 @@ def test_includes_and_excludes_combo(): assert car_excludable.is_excluded("aircon_type") assert car_excludable.is_included("name") - alias = Company.Meta.alias_manager.resolve_relation_alias(Car, "manufacturer") + alias = Company.ormar_config.alias_manager.resolve_relation_alias(Car, "manufacturer") manu_excludable = excludable.get(Company, alias=alias) assert manu_excludable.include == {"name"} assert manu_excludable.exclude == {"founded"} diff --git a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py index 1250c7c9f..ce5ab0e45 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py @@ -61,18 +61,17 @@ def gen_pass(): class RandomModel(ormar.Model): - class Meta: - tablename: str = "random_users" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="random_users", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) password: str = ormar.String(max_length=255, default=gen_pass) first_name: str = ormar.String(max_length=255, default="John") last_name: str = ormar.String(max_length=255) - created_date: datetime.datetime = ormar.DateTime( - server_default=sqlalchemy.func.now() - ) + created_date: datetime.datetime = ormar.DateTime(server_default=sqlalchemy.func.now()) @property_field def full_name(self) -> str: @@ -80,10 +79,11 @@ def full_name(self) -> str: class User(ormar.Model): - class Meta: - tablename: str = "users" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="users", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255) @@ -94,10 +94,11 @@ class Meta: class User2(ormar.Model): - class Meta: - tablename: str = "users2" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="users2", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255, nullable=False) @@ -105,9 +106,7 @@ class Meta: first_name: str = ormar.String(max_length=255) last_name: str = ormar.String(max_length=255) category: str = ormar.String(max_length=255, nullable=True) - timestamp: datetime.datetime = ormar.DateTime( - pydantic_only=True, default=datetime.datetime.now - ) + timestamp: datetime.datetime = ormar.DateTime(pydantic_only=True, default=datetime.datetime.now) @pytest.fixture(autouse=True, scope="module") @@ -220,12 +219,7 @@ async def test_excluding_fields_in_endpoints(): "category", "timestamp", ] - assert ( - datetime.datetime.strptime( - response.json().get("timestamp"), "%Y-%m-%dT%H:%M:%S.%f" - ) - == timestamp - ) + assert datetime.datetime.strptime(response.json().get("timestamp"), "%Y-%m-%dT%H:%M:%S.%f") == timestamp @pytest.mark.asyncio diff --git a/tests/test_exclude_include_dict/test_excluding_fields_with_default.py b/tests/test_exclude_include_dict/test_excluding_fields_with_default.py index f27274b4e..250a1d1fe 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_with_default.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_with_default.py @@ -17,10 +17,11 @@ def get_position() -> int: class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="albums", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -28,10 +29,11 @@ class Meta: class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="tracks", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -101,9 +103,7 @@ async def test_excluding_field_with_default(): album = ( await Album.objects.select_related("tracks") - .exclude_fields( - {"is_best_seller": ..., "tracks": {"play_count", "position"}} - ) + .exclude_fields({"is_best_seller": ..., "tracks": {"play_count", "position"}}) .get(name="Miami") ) assert album.is_best_seller is None diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index dd9ac571d..591fd6a34 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -13,10 +13,11 @@ class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "companies", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False) @@ -24,10 +25,11 @@ class Meta: class Car(ormar.Model): - class Meta: - tablename = "cars" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "cars", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) manufacturer: Optional[Company] = ormar.ForeignKey(Company) @@ -173,7 +175,7 @@ async def test_selecting_subset(): assert car.manufacturer.name == "Toyota" assert car.manufacturer.founded is None - with pytest.raises(pydantic.error_wrappers.ValidationError): + with pytest.raises(pydantic.ValidationError): # cannot exclude mandatory model columns - company__name in this example await Car.objects.select_related("manufacturer").exclude_fields( ["manufacturer__name"] diff --git a/tests/test_exclude_include_dict/test_pydantic_dict_params.py b/tests/test_exclude_include_dict/test_pydantic_dict_params.py index 474580e4f..6a925193d 100644 --- a/tests/test_exclude_include_dict/test_pydantic_dict_params.py +++ b/tests/test_exclude_include_dict/test_pydantic_dict_params.py @@ -12,10 +12,11 @@ class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="categories", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="Test", nullable=True) @@ -23,10 +24,11 @@ class Meta: class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="items", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -63,7 +65,7 @@ async def test_exclude_default(): "visibility": True, } assert category2.dict(exclude_defaults=True) == {"id": 1, "items": []} - assert category2.json(exclude_defaults=True) == '{"id": 1, "items": []}' + assert category2.json(exclude_defaults=True) == '{"id":1,"items":[]}' @pytest.mark.asyncio @@ -95,10 +97,7 @@ async def test_exclude_none(): "items": [], "visibility": True, } - assert ( - category2.json(exclude_none=True) - == '{"id": 2, "visibility": true, "items": []}' - ) + assert category2.json(exclude_none=True) == '{"id":2,"visibility":true,"items":[]}' @pytest.mark.asyncio diff --git a/tests/test_fastapi/test_binary_fields.py b/tests/test_fastapi/test_binary_fields.py index 39e82a3b8..5dce624e5 100644 --- a/tests/test_fastapi/test_binary_fields.py +++ b/tests/test_fastapi/test_binary_fields.py @@ -42,14 +42,13 @@ async def shutdown() -> None: blob6 = b"\xff" -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class BinaryThing(ormar.Model): - class Meta(BaseMeta): - tablename = "things" + ormar_config = base_ormar_config.copy(tablename = "things") id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.Text(default="") diff --git a/tests/test_fastapi/test_choices_schema.py b/tests/test_fastapi/test_choices_schema.py deleted file mode 100644 index dda330675..000000000 --- a/tests/test_fastapi/test_choices_schema.py +++ /dev/null @@ -1,151 +0,0 @@ -import datetime -import decimal -import uuid -from enum import Enum - -import databases -import pydantic -import pytest -import sqlalchemy -from asgi_lifespan import LifespanManager -from fastapi import FastAPI -from httpx import AsyncClient - -import ormar -from tests.settings import DATABASE_URL - -app = FastAPI() -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() -app.state.database = database - -uuid1 = uuid.uuid4() -uuid2 = uuid.uuid4() - - -blob = b"test" -blob2 = b"test2icac89uc98" - - -class EnumTest(Enum): - val1 = "Val1" - val2 = "Val2" - - -class Organisation(ormar.Model): - class Meta: - tablename = "org" - metadata = metadata - database = database - - id: int = ormar.Integer(primary_key=True) - ident: str = ormar.String(max_length=100, choices=["ACME Ltd", "Other ltd"]) - priority: int = ormar.Integer(choices=[1, 2, 3, 4, 5]) - priority2: int = ormar.BigInteger(choices=[1, 2, 3, 4, 5]) - priority3: int = ormar.SmallInteger(choices=[1, 2, 3, 4, 5]) - expire_date: datetime.date = ormar.Date( - choices=[datetime.date(2021, 1, 1), datetime.date(2022, 5, 1)] - ) - expire_time: datetime.time = ormar.Time( - choices=[datetime.time(10, 0, 0), datetime.time(12, 30)] - ) - - expire_datetime: datetime.datetime = ormar.DateTime( - choices=[ - datetime.datetime(2021, 1, 1, 10, 0, 0), - datetime.datetime(2022, 5, 1, 12, 30), - ] - ) - random_val: float = ormar.Float(choices=[2.0, 3.5]) - random_decimal: decimal.Decimal = ormar.Decimal( - scale=2, precision=4, choices=[decimal.Decimal(12.4), decimal.Decimal(58.2)] - ) - random_json: pydantic.Json = ormar.JSON(choices=["aa", '{"aa": "bb"}']) - random_uuid: uuid.UUID = ormar.UUID(choices=[uuid1, uuid2]) - enum_string: str = ormar.String(max_length=100, choices=list(EnumTest)) - blob_col: bytes = ormar.LargeBinary(max_length=100000, choices=[blob, blob2]) - - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() - - -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) - - -@app.post("/items/", response_model=Organisation) -async def create_item(item: Organisation): - await item.save() - return item - - -@pytest.mark.asyncio -async def test_all_endpoints(): - client = AsyncClient(app=app, base_url="http://testserver") - async with client as client, LifespanManager(app): - response = await client.post( - "/items/", - json={"id": 1, "ident": "", "priority": 4, "expire_date": "2022-05-01"}, - ) - - assert response.status_code == 422 - response = await client.post( - "/items/", - json={ - "id": 1, - "ident": "ACME Ltd", - "priority": 4, - "priority2": 2, - "priority3": 1, - "expire_date": "2022-05-01", - "expire_time": "10:00:00", - "expire_datetime": "2022-05-01T12:30:00", - "random_val": 3.5, - "random_decimal": 12.4, - "random_json": '{"aa": "bb"}', - "random_uuid": str(uuid1), - "enum_string": EnumTest.val1.value, - "blob_col": blob.decode("utf-8"), - }, - ) - assert response.status_code == 200 - item = Organisation(**response.json()) - assert item.pk is not None - response = await client.get("/docs") - assert response.status_code == 200 - assert b"FastAPI - Swagger UI" in response.content - - -def test_schema_modification(): - schema = Organisation.schema() - for field in ["ident", "priority", "expire_date"]: - assert field in schema["properties"] - assert schema["properties"].get(field).get("enum") == list( - Organisation.Meta.model_fields.get(field).choices - ) - assert "An enumeration." in schema["properties"].get(field).get("description") - - -def test_schema_gen(): - schema = app.openapi() - assert "Organisation" in schema["components"]["schemas"] - props = schema["components"]["schemas"]["Organisation"]["properties"] - for field in [k for k in Organisation.Meta.model_fields.keys() if k != "id"]: - assert "enum" in props.get(field) - assert "description" in props.get(field) - assert "An enumeration." in props.get(field).get("description") diff --git a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py index 7aae2fecd..ebe863aab 100644 --- a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py +++ b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py @@ -16,22 +16,20 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class CA(ormar.Model): - class Meta(BaseMeta): - tablename = "cas" + ormar_config = base_ormar_config.copy( tablename = "cas") id: UUID = ormar.UUID(primary_key=True, default=uuid4) ca_name: str = ormar.Text(default="") class CB1(ormar.Model): - class Meta(BaseMeta): - tablename = "cb1s" + ormar_config = base_ormar_config.copy( tablename = "cb1s") id: UUID = ormar.UUID(primary_key=True, default=uuid4) cb1_name: str = ormar.Text(default="") @@ -39,8 +37,7 @@ class Meta(BaseMeta): class CB2(ormar.Model): - class Meta(BaseMeta): - tablename = "cb2s" + ormar_config = base_ormar_config.copy(tablename = "cb2s") id: UUID = ormar.UUID(primary_key=True, default=uuid4) cb2_name: str = ormar.Text(default="") diff --git a/tests/test_fastapi/test_enum_schema.py b/tests/test_fastapi/test_enum_schema.py index 6fa3ce1df..1fccf1ab3 100644 --- a/tests/test_fastapi/test_enum_schema.py +++ b/tests/test_fastapi/test_enum_schema.py @@ -16,10 +16,11 @@ class MyEnum(Enum): class EnumExample(ormar.Model): - class Meta: - tablename = "enum_example" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="enum_example", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) size: MyEnum = ormar.Enum(enum_class=MyEnum, default=MyEnum.SMALL) @@ -27,7 +28,4 @@ class Meta: def test_proper_schema(): schema = EnumExample.schema_json() - assert ( - '{"MyEnum": {"title": "MyEnum", "description": "An enumeration.", ' - '"enum": [1, 2]}}' in schema - ) + assert '{"MyEnum": {"title": "MyEnum", "description": "An enumeration.", ' '"enum": [1, 2]}}' in schema diff --git a/tests/test_fastapi/test_excluding_fields.py b/tests/test_fastapi/test_excluding_fields.py index 7acf89682..6a2fb5f1c 100644 --- a/tests/test_fastapi/test_excluding_fields.py +++ b/tests/test_fastapi/test_excluding_fields.py @@ -31,20 +31,22 @@ async def shutdown() -> None: class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "categories", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "items", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_fastapi/test_extra_ignore_parameter.py b/tests/test_fastapi/test_extra_ignore_parameter.py index 967f7b8ee..954b541cc 100644 --- a/tests/test_fastapi/test_extra_ignore_parameter.py +++ b/tests/test_fastapi/test_extra_ignore_parameter.py @@ -32,10 +32,11 @@ async def shutdown() -> None: class Item(ormar.Model): - class Meta: - database = database - metadata = metadata - extra = Extra.ignore + ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + extra = Extra.ignore, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index c58621639..19e4cdea5 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -32,9 +32,10 @@ async def shutdown() -> None: await database_.disconnect() -class LocalMeta: - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class PTestA(pydantic.BaseModel): @@ -49,21 +50,19 @@ class PTestP(pydantic.BaseModel): class Category(ormar.Model): - class Meta(LocalMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta(LocalMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) - pydantic_int: Optional[int] - test_P: Optional[List[PTestP]] + pydantic_int: Optional[int] = None + test_P: Optional[List[PTestP]] = None categories = ormar.ManyToMany(Category) @@ -112,16 +111,12 @@ async def test_all_endpoints(): item = Item(**response.json()) assert item.pk is not None - response = await client.post( - "/items/add_category/", json={"item": item.dict(), "category": category} - ) + response = await client.post("/items/add_category/", json={"item": item.dict(), "category": category}) item = Item(**response.json()) assert len(item.categories) == 1 assert item.categories[0].name == "test cat" - await client.post( - "/items/add_category/", json={"item": item.dict(), "category": category2} - ) + await client.post("/items/add_category/", json={"item": item.dict(), "category": category2}) response = await client.get("/items/") items = [Item(**item) for item in response.json()] @@ -137,9 +132,7 @@ async def test_all_endpoints(): def test_schema_modification(): schema = Item.schema() - assert any( - x.get("type") == "array" for x in schema["properties"]["categories"]["anyOf"] - ) + assert any(x.get("type") == "array" for x in schema["properties"]["categories"]["anyOf"]) assert schema["properties"]["categories"]["title"] == "Categories" assert schema["example"] == { "categories": [{"id": 0, "name": "string"}], @@ -158,9 +151,7 @@ def test_schema_modification(): "id": 0, "name": "string", "pydantic_int": 0, - "test_P": [ - {"a": 0, "b": {"c": "string", "d": "string", "e": "string"}} - ], + "test_P": [{"a": 0, "b": {"c": "string", "d": "string", "e": "string"}}], } ], } diff --git a/tests/test_fastapi/test_fastapi_usage.py b/tests/test_fastapi/test_fastapi_usage.py index 8a8310546..29a2ad9fe 100644 --- a/tests/test_fastapi/test_fastapi_usage.py +++ b/tests/test_fastapi/test_fastapi_usage.py @@ -17,20 +17,22 @@ class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "categories", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "items", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_fastapi/test_json_field_fastapi.py b/tests/test_fastapi/test_json_field_fastapi.py index cd883ea91..f168e8c90 100644 --- a/tests/test_fastapi/test_json_field_fastapi.py +++ b/tests/test_fastapi/test_json_field_fastapi.py @@ -34,14 +34,13 @@ async def shutdown() -> None: await database_.disconnect() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Thing(ormar.Model): - class Meta(BaseMeta): - tablename = "things" + ormar_config = base_ormar_config.copy(tablename = "things") id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.Text(default="") @@ -104,8 +103,7 @@ async def test_json_is_required_if_not_nullable(): @pytest.mark.asyncio async def test_json_is_not_required_if_nullable(): class Thing2(ormar.Model): - class Meta(BaseMeta): - tablename = "things2" + ormar_config = base_ormar_config.copy( tablename = "things2") id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.Text(default="") diff --git a/tests/test_fastapi/test_m2m_forwardref.py b/tests/test_fastapi/test_m2m_forwardref.py index 61784e071..4cfcfaebd 100644 --- a/tests/test_fastapi/test_m2m_forwardref.py +++ b/tests/test_fastapi/test_m2m_forwardref.py @@ -5,7 +5,7 @@ import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI -from pydantic.schema import ForwardRef +from typing import ForwardRef from starlette import status from httpx import AsyncClient @@ -46,8 +46,8 @@ async def shutdown() -> None: # models.py class Country(ormar.Model): - class Meta(BaseMeta): - tablename = "countries" + ormar_config = base_ormar_config.copy(tablename = "countries") + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128, unique=True) @@ -65,8 +65,8 @@ class Meta(BaseMeta): class City(ormar.Model): - class Meta(BaseMeta): - tablename = "cities" + ormar_config = base_ormar_config.copy(tablename = "cities") + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128) diff --git a/tests/test_fastapi/test_more_reallife_fastapi.py b/tests/test_fastapi/test_more_reallife_fastapi.py index 421afa87a..5dec1f6bf 100644 --- a/tests/test_fastapi/test_more_reallife_fastapi.py +++ b/tests/test_fastapi/test_more_reallife_fastapi.py @@ -31,20 +31,22 @@ async def shutdown() -> None: class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "categories", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "items", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_fastapi/test_nested_saving.py b/tests/test_fastapi/test_nested_saving.py index 44f106467..81da2763c 100644 --- a/tests/test_fastapi/test_nested_saving.py +++ b/tests/test_fastapi/test_nested_saving.py @@ -35,18 +35,20 @@ async def shutdown() -> None: class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) department_name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) course_name: str = ormar.String(max_length=100) @@ -55,9 +57,10 @@ class Meta: class Student(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_fastapi/test_recursion_error.py b/tests/test_fastapi/test_recursion_error.py index 1e1e25480..6dbbd060c 100644 --- a/tests/test_fastapi/test_recursion_error.py +++ b/tests/test_fastapi/test_recursion_error.py @@ -49,10 +49,11 @@ class User(ormar.Model): verify_key: str = ormar.String(unique=True, max_length=100, nullable=True) created_at: datetime = ormar.DateTime(default=datetime.now()) - class Meta: - tablename = "users" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "users", + metadata = metadata, + database = database, + ) class UserSession(ormar.Model): @@ -65,10 +66,11 @@ class UserSession(ormar.Model): session_key: str = ormar.String(unique=True, max_length=64) created_at: datetime = ormar.DateTime(default=datetime.now()) - class Meta: - tablename = "user_sessions" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "user_sessions", + metadata = metadata, + database = database, + ) class QuizAnswer(BaseModel): @@ -96,10 +98,11 @@ class Quiz(ormar.Model): user_id: uuid.UUID = ormar.UUID(foreign_key=User.id) questions: Json = ormar.JSON(nullable=False) - class Meta: - tablename = "quiz" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "quiz", + metadata = metadata, + database = database, + ) @pytest.fixture(autouse=True, scope="module") diff --git a/tests/test_fastapi/test_relations_with_nested_defaults.py b/tests/test_fastapi/test_relations_with_nested_defaults.py index 1b8cfbb02..db4601fdd 100644 --- a/tests/test_fastapi/test_relations_with_nested_defaults.py +++ b/tests/test_fastapi/test_relations_with_nested_defaults.py @@ -32,22 +32,22 @@ async def shutdown() -> None: await database_.disconnect() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Country(ormar.Model): - class Meta(BaseMeta): - tablename = "countries" + ormar_config = base_ormar_config.copy( tablename = "countries") + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="Poland") class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy( tablename = "authors") + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -56,8 +56,8 @@ class Meta(BaseMeta): class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy( tablename = "books") + id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) diff --git a/tests/test_fastapi/test_schema_not_allowed_params.py b/tests/test_fastapi/test_schema_not_allowed_params.py index bc24a089e..3b0ccc4e7 100644 --- a/tests/test_fastapi/test_schema_not_allowed_params.py +++ b/tests/test_fastapi/test_schema_not_allowed_params.py @@ -8,14 +8,13 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename = "authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_fastapi/test_skip_reverse_models.py b/tests/test_fastapi/test_skip_reverse_models.py index 9aa20f1b6..576d16cc1 100644 --- a/tests/test_fastapi/test_skip_reverse_models.py +++ b/tests/test_fastapi/test_skip_reverse_models.py @@ -39,8 +39,7 @@ async def shutdown() -> None: class Author(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -48,16 +47,14 @@ class Meta(BaseMeta): class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename = "categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -140,7 +137,7 @@ async def test_queries(): response = await client.post("/posts/", json=right_post, headers=headers) assert response.status_code == 200 - Category.__config__.extra = "allow" + Category.model_config["extra"] = "allow" response = await client.get("/posts/") assert response.status_code == 200 posts = [Post(**x) for x in response.json()] diff --git a/tests/test_fastapi/test_wekref_exclusion.py b/tests/test_fastapi/test_wekref_exclusion.py index c93b7a892..6f20fa61f 100644 --- a/tests/test_fastapi/test_wekref_exclusion.py +++ b/tests/test_fastapi/test_wekref_exclusion.py @@ -49,8 +49,7 @@ def create_test_database(): class OtherThing(ormar.Model): - class Meta(BaseMeta): - tablename = "other_things" + ormar_config = base_ormar_config.copy( tablename = "other_things") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.Text(default="") @@ -58,8 +57,7 @@ class Meta(BaseMeta): class Thing(ormar.Model): - class Meta(BaseMeta): - tablename = "things" + ormar_config = base_ormar_config.copy(tablename = "things") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.Text(default="") diff --git a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py index ade7085ab..fdf3bb52a 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py +++ b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py @@ -14,36 +14,40 @@ class User(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "users" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "users", + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) class RelationalAuditModel(ormar.Model): - class Meta: + ormar_config = ormar.OrmarConfig( abstract = True + ) created_by: User = ormar.ForeignKey(User, nullable=False) updated_by: User = ormar.ForeignKey(User, nullable=False) class AuditModel(ormar.Model): - class Meta: + ormar_config = ormar.OrmarConfig( abstract = True + ) created_by: str = ormar.String(max_length=100) updated_by: str = ormar.String(max_length=100, default="Sam") class DateFieldsModel(ormar.Model): - class Meta(ormar.ModelMeta): - abstract = True - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + abstract = True, + metadata = metadata, + database = db, + ) created_date: datetime.datetime = ormar.DateTime( default=datetime.datetime.now, name="creation_date" @@ -54,9 +58,10 @@ class Meta(ormar.ModelMeta): class Category(DateFieldsModel, AuditModel): - class Meta(ormar.ModelMeta): - tablename = "categories" - exclude_parent_fields = ["updated_by", "updated_date"] + ormar_config = ormar.OrmarConfig( + tablename = "categories", + exclude_parent_fields = ["updated_by", "updated_date"], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -64,9 +69,10 @@ class Meta(ormar.ModelMeta): class Item(DateFieldsModel, AuditModel): - class Meta(ormar.ModelMeta): - tablename = "items" - exclude_parent_fields = ["updated_by", "updated_date"] + ormar_config = ormar.OrmarConfig( + tablename = "items", + exclude_parent_fields = ["updated_by", "updated_date"], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -75,9 +81,10 @@ class Meta(ormar.ModelMeta): class Gun(RelationalAuditModel, DateFieldsModel): - class Meta(ormar.ModelMeta): - tablename = "guns" - exclude_parent_fields = ["updated_by"] + ormar_config = ormar.OrmarConfig( + tablename = "guns", + exclude_parent_fields = ["updated_by"], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) @@ -91,8 +98,8 @@ def create_test_database(): def test_model_definition(): - model_fields = Category.Meta.model_fields - sqlalchemy_columns = Category.Meta.table.c + model_fields = Category.ormar_config.model_fields + sqlalchemy_columns = Category.ormar_config.table.c pydantic_columns = Category.__fields__ assert "updated_by" not in model_fields assert "updated_by" not in sqlalchemy_columns @@ -101,8 +108,8 @@ def test_model_definition(): assert "updated_date" not in sqlalchemy_columns assert "updated_date" not in pydantic_columns - assert "updated_by" not in Gun.Meta.model_fields - assert "updated_by" not in Gun.Meta.table.c + assert "updated_by" not in Gun.ormar_config.model_fields + assert "updated_by" not in Gun.ormar_config.table.c assert "updated_by" not in Gun.__fields__ diff --git a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py index 146c87f0b..3f3754564 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py +++ b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py @@ -3,8 +3,7 @@ import databases import pydantic import sqlalchemy -from pydantic import ConstrainedStr -from pydantic.typing import ForwardRef +from typing import ForwardRef import ormar from tests.settings import DATABASE_URL @@ -13,14 +12,13 @@ database = databases.Database(DATABASE_URL, force_rollback=True) -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class SelfRef(ormar.Model): - class Meta(BaseMeta): - tablename = "self_refs" + ormar_config = base_ormar_config.copy(tablename = "self_refs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="selfref") @@ -31,16 +29,14 @@ class Meta(BaseMeta): class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename = "categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="test") @@ -48,16 +44,14 @@ class Meta(BaseMeta): class MutualA(ormar.Model): - class Meta(BaseMeta): - tablename = "mutual_a" + ormar_config = base_ormar_config.copy(tablename = "mutual_a") id: int = ormar.Integer(primary_key=True) mutual_b = ormar.ForeignKey(ForwardRef("MutualB"), related_name="mutuals_a") class MutualB(ormar.Model): - class Meta(BaseMeta): - tablename = "mutual_b" + ormar_config = base_ormar_config.copy(tablename = "mutual_b") id: int = ormar.Integer(primary_key=True) name = ormar.String(max_length=100, default="test") @@ -77,7 +71,7 @@ def test_getting_pydantic_model(): assert PydanticCategory.__fields__["id"].default is None assert PydanticCategory.__fields__["name"].required - assert issubclass(PydanticCategory.__fields__["name"].outer_type_, ConstrainedStr) + assert issubclass(PydanticCategory.__fields__["name"].outer_type_, str) assert PydanticCategory.__fields__["name"].default in [None, Ellipsis] PydanticItem = PydanticCategory.__fields__["items"].type_ @@ -85,7 +79,7 @@ def test_getting_pydantic_model(): assert issubclass(PydanticItem, pydantic.BaseModel) assert not PydanticItem.__fields__["name"].required assert PydanticItem.__fields__["name"].default == "test" - assert issubclass(PydanticItem.__fields__["name"].outer_type_, ConstrainedStr) + assert issubclass(PydanticItem.__fields__["name"].outer_type_, str) assert "category" not in PydanticItem.__fields__ diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index ccaf27faa..b76746be8 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -21,8 +21,9 @@ class AuditModel(ormar.Model): - class Meta: - abstract = True + ormar_config = ormar.OrmarConfig( + abstract=True, + ) created_by: str = ormar.String(max_length=100) updated_by: str = ormar.String(max_length=100, default="Sam") @@ -33,10 +34,11 @@ def audit(self): # pragma: no cover class DateFieldsModelNoSubclass(ormar.Model): - class Meta: - tablename = "test_date_models" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename="test_date_models", + metadata=metadata, + database=db, + ) date_id: int = ormar.Integer(primary_key=True) created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) @@ -44,11 +46,11 @@ class Meta: class DateFieldsModel(ormar.Model): - class Meta: - abstract = True - metadata = metadata - database = db - constraints = [ + ormar_config = ormar.OrmarConfig( + abstract=True, + metadata=metadata, + database=db, + constraints=[ ormar.fields.constraints.UniqueColumns( "creation_date", "modification_date", @@ -56,20 +58,17 @@ class Meta: ormar.fields.constraints.CheckColumns( "creation_date <= modification_date", ), - ] - - created_date: datetime.datetime = ormar.DateTime( - default=datetime.datetime.now, name="creation_date" - ) - updated_date: datetime.datetime = ormar.DateTime( - default=datetime.datetime.now, name="modification_date" + ], ) + created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now, name="creation_date") + updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now, name="modification_date") + class Category(DateFieldsModel, AuditModel): - class Meta(ormar.ModelMeta): - tablename = "categories" - constraints = [ormar.fields.constraints.UniqueColumns("name", "code")] + ormar_config = ormar.OrmarConfig( + tablename="categories", constraints=[ormar.fields.constraints.UniqueColumns("name", "code")] + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -85,8 +84,7 @@ def audit(self): class Subject(DateFieldsModel): - class Meta(ormar.ModelMeta): - pass + ormar_config = ormar.OrmarConfig() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -94,19 +92,21 @@ class Meta(ormar.ModelMeta): class Person(ormar.Model): - class Meta: - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Car(ormar.Model): - class Meta: - abstract = True - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + abstract=True, + metadata=metadata, + database=db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) @@ -116,27 +116,28 @@ class Meta: class Truck(Car): - class Meta: - pass + ormar_config = ormar.OrmarConfig() max_capacity: int = ormar.Integer() class Bus(Car): - class Meta: - tablename = "buses" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename="buses", + metadata=metadata, + database=db, + ) owner: Person = ormar.ForeignKey(Person, related_name="buses") max_persons: int = ormar.Integer() class Car2(ormar.Model): - class Meta: - abstract = True - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + abstract=True, + metadata=metadata, + database=db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) @@ -146,23 +147,21 @@ class Meta: class Truck2(Car2): - class Meta: - tablename = "trucks2" + ormar_config = ormar.OrmarConfig(tablename="trucks2") max_capacity: int = ormar.Integer() class Bus2(Car2): - class Meta: - tablename = "buses2" + ormar_config = ormar.OrmarConfig(tablename="buses2") max_persons: int = ormar.Integer() class ImmutablePerson(Person): - class Config: - allow_mutation = False - validate_assignment = False + model_config = dict( + allow_mutation = False, + validate_assignment = False) @pytest.fixture(autouse=True, scope="module") @@ -181,8 +180,7 @@ def test_duplicated_related_name_on_different_model(): with pytest.raises(ModelDefinitionError): class Bus3(Car2): # pragma: no cover - class Meta: - tablename = "buses3" + ormar_config = ormar.OrmarConfig(tablename="buses3") owner: Person = ormar.ForeignKey(Person, related_name="buses") max_persons: int = ormar.Integer() @@ -197,31 +195,31 @@ class ImmutablePerson2(Person): def test_field_redefining_in_concrete_models(): class RedefinedField(DateFieldsModel): - class Meta(ormar.ModelMeta): - tablename = "redefines" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename="redefines", + metadata=metadata, + database=db, + ) id: int = ormar.Integer(primary_key=True) created_date: str = ormar.String(max_length=200, name="creation_date") - changed_field = RedefinedField.Meta.model_fields["created_date"] + changed_field = RedefinedField.ormar_config.model_fields["created_date"] assert changed_field.ormar_default is None assert changed_field.get_alias() == "creation_date" - assert any(x.name == "creation_date" for x in RedefinedField.Meta.table.columns) - assert isinstance( - RedefinedField.Meta.table.columns["creation_date"].type, sa.sql.sqltypes.String - ) + assert any(x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns) + assert isinstance(RedefinedField.ormar_config.table.columns["creation_date"].type, sa.sql.sqltypes.String) def test_model_subclassing_that_redefines_constraints_column_names(): with pytest.raises(ModelDefinitionError): class WrongField2(DateFieldsModel): # pragma: no cover - class Meta(ormar.ModelMeta): - tablename = "wrongs" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename="wrongs", + metadata=metadata, + database=db, + ) id: int = ormar.Integer(primary_key=True) created_date: str = ormar.String(max_length=200) @@ -231,20 +229,21 @@ def test_model_subclassing_non_abstract_raises_error(): with pytest.raises(ModelDefinitionError): class WrongField2(DateFieldsModelNoSubclass): # pragma: no cover - class Meta(ormar.ModelMeta): - tablename = "wrongs" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename="wrongs", + metadata=metadata, + database=db, + ) id: int = ormar.Integer(primary_key=True) def test_params_are_inherited(): - assert Category.Meta.metadata == metadata - assert Category.Meta.database == db - assert len(Category.Meta.property_fields) == 2 + assert Category.ormar_config.metadata == metadata + assert Category.ormar_config.database == db + assert len(Category.ormar_config.property_fields) == 2 - constraints = Counter(map(lambda c: type(c), Category.Meta.constraints)) + constraints = Counter(map(lambda c: type(c), Category.ormar_config.constraints)) assert constraints[ormar.fields.constraints.UniqueColumns] == 2 assert constraints[ormar.fields.constraints.IndexColumns] == 0 assert constraints[ormar.fields.constraints.CheckColumns] == 1 @@ -262,31 +261,25 @@ def round_date_to_seconds( async def test_fields_inherited_from_mixin(): async with db: async with db.transaction(force_rollback=True): - cat = await Category( - name="Foo", code=123, created_by="Sam", updated_by="Max" - ).save() + cat = await Category(name="Foo", code=123, created_by="Sam", updated_by="Max").save() sub = await Subject(name="Bar", category=cat).save() mixin_columns = ["created_date", "updated_date"] mixin_db_columns = ["creation_date", "modification_date"] mixin2_columns = ["created_by", "updated_by"] - assert all(field in Category.Meta.model_fields for field in mixin_columns) + assert all(field in Category.ormar_config.model_fields for field in mixin_columns) assert cat.created_date is not None assert cat.updated_date is not None - assert all(field in Subject.Meta.model_fields for field in mixin_columns) + assert all(field in Subject.ormar_config.model_fields for field in mixin_columns) assert sub.created_date is not None assert sub.updated_date is not None - assert all(field in Category.Meta.model_fields for field in mixin2_columns) - assert all( - field not in Subject.Meta.model_fields for field in mixin2_columns - ) + assert all(field in Category.ormar_config.model_fields for field in mixin2_columns) + assert all(field not in Subject.ormar_config.model_fields for field in mixin2_columns) inspector = sa.inspect(engine) assert "categories" in inspector.get_table_names() table_columns = [x.get("name") for x in inspector.get_columns("categories")] - assert all( - col in table_columns for col in mixin_db_columns - ) # + mixin2_columns) + assert all(col in table_columns for col in mixin_db_columns) # + mixin2_columns) assert "subjects" in inspector.get_table_names() table_columns = [x.get("name") for x in inspector.get_columns("subjects")] @@ -298,13 +291,9 @@ async def test_fields_inherited_from_mixin(): .exclude_fields("updated_date") .get() ) - assert round_date_to_seconds(sub2.created_date) == round_date_to_seconds( - sub.created_date - ) + assert round_date_to_seconds(sub2.created_date) == round_date_to_seconds(sub.created_date) assert sub2.category.updated_date is not None - assert round_date_to_seconds( - sub2.category.created_date - ) == round_date_to_seconds(cat.created_date) + assert round_date_to_seconds(sub2.category.created_date) == round_date_to_seconds(cat.created_date) assert sub2.updated_date is None assert sub2.category.created_by == "Sam" assert sub2.category.updated_by == cat.updated_by @@ -315,13 +304,9 @@ async def test_fields_inherited_from_mixin(): .exclude_fields({"updated_date": ..., "category": {"updated_date"}}) .get() ) - assert round_date_to_seconds(sub3.created_date) == round_date_to_seconds( - sub.created_date - ) + assert round_date_to_seconds(sub3.created_date) == round_date_to_seconds(sub.created_date) assert sub3.category.updated_date is None - assert round_date_to_seconds( - sub3.category.created_date - ) == round_date_to_seconds(cat.created_date) + assert round_date_to_seconds(sub3.category.created_date) == round_date_to_seconds(cat.created_date) assert sub3.updated_date is None assert sub3.category.created_by == "Sam" assert sub3.category.updated_by == cat.updated_by @@ -333,9 +318,7 @@ async def test_inheritance_with_relation(): async with db.transaction(force_rollback=True): sam = await Person(name="Sam").save() joe = await Person(name="Joe").save() - await Truck( - name="Shelby wanna be", max_capacity=1400, owner=sam, co_owner=joe - ).save() + await Truck(name="Shelby wanna be", max_capacity=1400, owner=sam, co_owner=joe).save() await Bus(name="Unicorn", max_persons=50, owner=sam, co_owner=joe).save() shelby = await Truck.objects.select_related(["owner", "co_owner"]).get() @@ -350,9 +333,7 @@ async def test_inheritance_with_relation(): assert unicorn.co_owner.name == "Joe" assert unicorn.max_persons == 50 - joe_check = await Person.objects.select_related( - ["coowned_trucks", "coowned_buses"] - ).get(name="Joe") + joe_check = await Person.objects.select_related(["coowned_trucks", "coowned_buses"]).get(name="Joe") assert joe_check.pk == joe.pk assert joe_check.coowned_trucks[0] == shelby assert joe_check.coowned_trucks[0].created_date is not None @@ -383,9 +364,7 @@ async def test_inheritance_with_multi_relation(): sam = await Person(name="Sam").save() joe = await Person(name="Joe").save() alex = await Person(name="Alex").save() - truck = await Truck2( - name="Shelby wanna be 2", max_capacity=1400, owner=sam - ).save() + truck = await Truck2(name="Shelby wanna be 2", max_capacity=1400, owner=sam).save() await truck.co_owners.add(joe) await truck.co_owners.add(alex) @@ -403,38 +382,26 @@ async def test_inheritance_with_multi_relation(): assert len(shelby.co_owners) == 2 assert shelby.max_capacity == 1400 - unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).get( - name="Unicorn 2" - ) + unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).get(name="Unicorn 2") assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert unicorn.co_owners[0].name == "Joe" assert len(unicorn.co_owners) == 2 assert unicorn.max_persons == 50 - unicorn = ( - await Bus2.objects.select_related(["owner", "co_owners"]) - .order_by("-co_owners__name") - .get() - ) + unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).order_by("-co_owners__name").get() assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert len(unicorn.co_owners) == 2 assert unicorn.co_owners[0].name == "Joe" - unicorn = ( - await Bus2.objects.select_related(["owner", "co_owners"]) - .order_by("co_owners__name") - .get() - ) + unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).order_by("co_owners__name").get() assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert len(unicorn.co_owners) == 2 assert unicorn.co_owners[0].name == "Alex" - joe_check = await Person.objects.select_related( - ["coowned_trucks2", "coowned_buses2"] - ).get(name="Joe") + joe_check = await Person.objects.select_related(["coowned_trucks2", "coowned_buses2"]).get(name="Joe") assert joe_check.pk == joe.pk assert joe_check.coowned_trucks2[0] == shelby assert joe_check.coowned_trucks2[0].created_date is not None @@ -461,22 +428,14 @@ async def test_inheritance_with_multi_relation(): await shelby.co_owners.remove(alex) await Truck2.objects.delete(name="Shelby wanna be 2") - unicorn = ( - await Bus2.objects.select_related(["owner", "co_owners"]) - .filter(co_owners__name="Joe") - .get() - ) + unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).filter(co_owners__name="Joe").get() assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert unicorn.co_owners[0].name == "Joe" assert len(unicorn.co_owners) == 1 assert unicorn.max_persons == 50 - unicorn = ( - await Bus2.objects.select_related(["owner", "co_owners"]) - .exclude(co_owners__name="Joe") - .get() - ) + unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).exclude(co_owners__name="Joe").get() assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert unicorn.co_owners[0].name == "Alex" diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py index b84fec36e..d21ec0bce 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py @@ -26,10 +26,11 @@ class DateFieldsMixins: class Category(ormar.Model, DateFieldsMixins, AuditMixin): - class Meta(ormar.ModelMeta): - tablename = "categories" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "categories", + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -37,10 +38,11 @@ class Meta(ormar.ModelMeta): class Subject(ormar.Model, DateFieldsMixins): - class Meta(ormar.ModelMeta): - tablename = "subjects" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "subjects", + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -56,46 +58,49 @@ def create_test_database(): def test_field_redefining(): class RedefinedField(ormar.Model, DateFieldsMixins): - class Meta(ormar.ModelMeta): - tablename = "redefined" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "redefined", + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) created_date: datetime.datetime = ormar.DateTime(name="creation_date") - assert RedefinedField.Meta.model_fields["created_date"].ormar_default is None + assert RedefinedField.ormar_config.model_fields["created_date"].ormar_default is None assert ( - RedefinedField.Meta.model_fields["created_date"].get_alias() == "creation_date" + RedefinedField.ormar_config.model_fields["created_date"].get_alias() == "creation_date" ) - assert any(x.name == "creation_date" for x in RedefinedField.Meta.table.columns) + assert any(x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns) def test_field_redefining_in_second_raises_error(): class OkField(ormar.Model, DateFieldsMixins): # pragma: no cover - class Meta(ormar.ModelMeta): - tablename = "oks" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "oks", + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) class RedefinedField2(ormar.Model, DateFieldsMixins): - class Meta(ormar.ModelMeta): - tablename = "redefines2" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "redefines2", + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) created_date: str = ormar.String(max_length=200, name="creation_date") - assert RedefinedField2.Meta.model_fields["created_date"].ormar_default is None + assert RedefinedField2.ormar_config.model_fields["created_date"].ormar_default is None assert ( - RedefinedField2.Meta.model_fields["created_date"].get_alias() == "creation_date" + RedefinedField2.ormar_config.model_fields["created_date"].get_alias() == "creation_date" ) - assert any(x.name == "creation_date" for x in RedefinedField2.Meta.table.columns) + assert any(x.name == "creation_date" for x in RedefinedField2.ormar_config.table.columns) assert isinstance( - RedefinedField2.Meta.table.columns["creation_date"].type, sa.sql.sqltypes.String + RedefinedField2.ormar_config.table.columns["creation_date"].type, sa.sql.sqltypes.String ) @@ -117,16 +122,16 @@ async def test_fields_inherited_from_mixin(): sub = await Subject(name="Bar", category=cat).save() mixin_columns = ["created_date", "updated_date"] mixin2_columns = ["created_by", "updated_by"] - assert all(field in Category.Meta.model_fields for field in mixin_columns) + assert all(field in Category.ormar_config.model_fields for field in mixin_columns) assert cat.created_date is not None assert cat.updated_date is not None - assert all(field in Subject.Meta.model_fields for field in mixin_columns) + assert all(field in Subject.ormar_config.model_fields for field in mixin_columns) assert sub.created_date is not None assert sub.updated_date is not None - assert all(field in Category.Meta.model_fields for field in mixin2_columns) + assert all(field in Category.ormar_config.model_fields for field in mixin2_columns) assert all( - field not in Subject.Meta.model_fields for field in mixin2_columns + field not in Subject.ormar_config.model_fields for field in mixin2_columns ) inspector = sa.inspect(engine) diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py index 9e9169f7c..c0a98f448 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py @@ -11,8 +11,8 @@ class BaseFoo(ormar.Model): - class Meta: - abstract = True + ormar_config = ormar.OrmarConfig( + abstract = True) name: str = ormar.String(max_length=100) @@ -22,9 +22,10 @@ def prefixed_name(self) -> str: class Foo(BaseFoo): - class Meta: - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + ) @ormar.property_field def double_prefixed_name(self) -> str: @@ -34,9 +35,10 @@ def double_prefixed_name(self) -> str: class Bar(BaseFoo): - class Meta: - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + ) @ormar.property_field def prefixed_name(self) -> str: diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py index 97ab138c9..9c487bfae 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py @@ -19,8 +19,7 @@ class BaseModel(ormar.Model): - class Meta(ormar.ModelMeta): - abstract = True + ormar_config = base_ormar_config.copy(abstract=True) id: uuid.UUID = ormar.UUID( primary_key=True, default=uuid.uuid4, uuid_format="string" @@ -30,8 +29,7 @@ class Meta(ormar.ModelMeta): class Member(BaseModel): - class Meta(BaseMeta): - tablename = "members" + ormar_config = base_ormar_config.copy(tablename="members") first_name: str = ormar.String(max_length=50) last_name: str = ormar.String(max_length=50) @@ -48,13 +46,13 @@ def create_test_database(): def test_model_structure(): assert "id" in BaseModel.__fields__ - assert "id" in BaseModel.Meta.model_fields - assert BaseModel.Meta.model_fields["id"].has_default() + assert "id" in BaseModel.ormar_config.model_fields + assert BaseModel.ormar_config.model_fields["id"].has_default() assert BaseModel.__fields__["id"].default_factory is not None assert "id" in Member.__fields__ - assert "id" in Member.Meta.model_fields - assert Member.Meta.model_fields["id"].has_default() + assert "id" in Member.ormar_config.model_fields + assert Member.ormar_config.model_fields["id"].has_default() assert Member.__fields__["id"].default_factory is not None diff --git a/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py b/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py index fc0851512..7258579ea 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py @@ -12,10 +12,11 @@ class TableBase(ormar.Model): - class Meta(ormar.ModelMeta): - abstract = True - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + abstract = True, + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) created_by: str = ormar.String(max_length=20, default="test") @@ -27,8 +28,9 @@ class Meta(ormar.ModelMeta): class NationBase(ormar.Model): - class Meta(ormar.ModelMeta): + ormar_config = ormar.OrmarConfig( abstract = True + ) name: str = ormar.String(max_length=50) alpha2_code: str = ormar.String(max_length=2) @@ -37,8 +39,7 @@ class Meta(ormar.ModelMeta): class Nation(NationBase, TableBase): - class Meta(ormar.ModelMeta): - pass + ormar_config = ormar.OrmarConfig() @pytest.fixture(autouse=True, scope="module") diff --git a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py index a96191c9a..c40ec1d78 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py @@ -8,22 +8,20 @@ database = databases.Database(DATABASE_URL, force_rollback=True) -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Library(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Package(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) library: Library = ormar.ForeignKey(Library, related_name="packages") @@ -31,8 +29,7 @@ class Meta(BaseMeta): class Ticket(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) number: int = ormar.Integer() @@ -40,8 +37,7 @@ class Meta(BaseMeta): class TicketPackage(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) status: str = ormar.String(max_length=100) diff --git a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py index 0169bec63..25b16fad8 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py +++ b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py @@ -16,9 +16,10 @@ class NewTestModel(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + ) a: int = ormar.Integer(primary_key=True) b: str = ormar.String(max_length=1) diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py index 1ff7c00b7..f9c1d327e 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py @@ -20,8 +20,9 @@ class BaseModel(ormar.Model): - class Meta: + ormar_config = ormar.OrmarConfig( abstract = True + ) id: int = ormar.Integer(primary_key=True) @@ -33,8 +34,7 @@ class EnumExample(str, enum.Enum): class ModelExample(BaseModel): - class Meta(BaseMeta): - tablename = "examples" + ormar_config = base_ormar_config.copy(tablename = "examples") str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) enum_field: str = ormar.String( diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py index 6f5813fb5..5439c0f29 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py @@ -27,10 +27,11 @@ class EnumExample(str, enum.Enum): class ModelExample(ormar.Model): - class Meta(ormar.ModelMeta): - database = database - metadata = metadata - tablename = "examples" + ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + tablename = "examples", + ) id: int = ormar.Integer(primary_key=True) str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) diff --git a/tests/test_meta_constraints/test_check_constraints.py b/tests/test_meta_constraints/test_check_constraints.py index 2fc69d4d2..66119a1ec 100644 --- a/tests/test_meta_constraints/test_check_constraints.py +++ b/tests/test_meta_constraints/test_check_constraints.py @@ -13,13 +13,13 @@ class Product(ormar.Model): - class Meta: - tablename = "products" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "products", + metadata = metadata, + database = database, constraints = [ ormar.fields.constraints.CheckColumns("inventory > buffer"), - ] + ]) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -39,7 +39,7 @@ def create_test_database(): @pytest.mark.asyncio async def test_check_columns_exclude_mysql(): - if Product.Meta.database._backend._dialect.name != "mysql": + if Product.ormar_config.database._backend._dialect.name != "mysql": async with database: # pragma: no cover async with database.transaction(force_rollback=True): await Product.objects.create( diff --git a/tests/test_meta_constraints/test_index_constraints.py b/tests/test_meta_constraints/test_index_constraints.py index 21bd1b603..217ca06a0 100644 --- a/tests/test_meta_constraints/test_index_constraints.py +++ b/tests/test_meta_constraints/test_index_constraints.py @@ -11,14 +11,15 @@ class Product(ormar.Model): - class Meta: - tablename = "products" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "products", + metadata = metadata, + database = database, constraints = [ ormar.fields.constraints.IndexColumns("company", "name", name="my_index"), ormar.fields.constraints.IndexColumns("location", "company_type"), ] + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -37,9 +38,9 @@ def create_test_database(): def test_table_structure(): - assert len(Product.Meta.table.indexes) > 0 + assert len(Product.ormar_config.table.indexes) > 0 indexes = sorted( - list(Product.Meta.table.indexes), key=lambda x: x.name, reverse=True + list(Product.ormar_config.table.indexes), key=lambda x: x.name, reverse=True ) test_index = indexes[0] assert test_index.name == "my_index" diff --git a/tests/test_meta_constraints/test_unique_constraints.py b/tests/test_meta_constraints/test_unique_constraints.py index 6a1bb5899..3d0536634 100644 --- a/tests/test_meta_constraints/test_unique_constraints.py +++ b/tests/test_meta_constraints/test_unique_constraints.py @@ -14,11 +14,12 @@ class Product(ormar.Model): - class Meta: - tablename = "products" - metadata = metadata - database = database - constraints = [ormar.fields.constraints.UniqueColumns("name", "company")] + ormar_config = ormar.OrmarConfig( + tablename = "products", + metadata = metadata, + database = database, + constraints = [ormar.fields.constraints.UniqueColumns("name", "company")], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_model_methods/test_load_all.py b/tests/test_model_methods/test_load_all.py index a6d3aaf98..9eb336618 100644 --- a/tests/test_model_methods/test_load_all.py +++ b/tests/test_model_methods/test_load_all.py @@ -18,8 +18,7 @@ class Language(ormar.Model): - class Meta(BaseMeta): - tablename = "languages" + ormar_config = base_ormar_config.copy(tablename = "languages") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -27,8 +26,7 @@ class Meta(BaseMeta): class CringeLevel(ormar.Model): - class Meta(BaseMeta): - tablename = "levels" + ormar_config = base_ormar_config.copy(tablename = "levels") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -36,8 +34,7 @@ class Meta(BaseMeta): class NickName(ormar.Model): - class Meta(BaseMeta): - tablename = "nicks" + ormar_config = base_ormar_config.copy(tablename = "nicks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -46,8 +43,7 @@ class Meta(BaseMeta): class HQ(ormar.Model): - class Meta(BaseMeta): - tablename = "hqs" + ormar_config = base_ormar_config.copy(tablename = "hqs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -55,8 +51,7 @@ class Meta(BaseMeta): class Company(ormar.Model): - class Meta(BaseMeta): - tablename = "companies" + ormar_config = base_ormar_config.copy(tablename = "companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") diff --git a/tests/test_ordering/test_default_model_order.py b/tests/test_ordering/test_default_model_order.py index 1b84ce0bc..2bde5f2ff 100644 --- a/tests/test_ordering/test_default_model_order.py +++ b/tests/test_ordering/test_default_model_order.py @@ -12,24 +12,21 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" - orders_by = ["-name"] + ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"]) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" - orders_by = ["year", "-ranking"] + ormar_config = base_ormar_config.copy(tablename="books", order_by=["year", "-ranking"]) id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -80,12 +77,8 @@ async def test_default_orders_is_applied(): async def test_default_orders_is_applied_on_related(): async with database: tolkien = await Author(name="J.R.R. Tolkien").save() - silmarillion = await Book( - author=tolkien, title="The Silmarillion", year=1977 - ).save() - lotr = await Book( - author=tolkien, title="The Lord of the Rings", year=1955 - ).save() + silmarillion = await Book(author=tolkien, title="The Silmarillion", year=1977).save() + lotr = await Book(author=tolkien, title="The Lord of the Rings", year=1955).save() hobbit = await Book(author=tolkien, title="The Hobbit", year=1933).save() await tolkien.books.all() @@ -103,13 +96,9 @@ async def test_default_orders_is_applied_on_related(): async def test_default_orders_is_applied_on_related_two_fields(): async with database: sanders = await Author(name="Brandon Sanderson").save() - twok = await Book( - author=sanders, title="The Way of Kings", year=2010, ranking=10 - ).save() + twok = await Book(author=sanders, title="The Way of Kings", year=2010, ranking=10).save() bret = await Author(name="Peter V. Bret").save() - tds = await Book( - author=bret, title="The Desert Spear", year=2010, ranking=9 - ).save() + tds = await Book(author=bret, title="The Desert Spear", year=2010, ranking=9).save() books = await Book.objects.all() assert books[0] == twok diff --git a/tests/test_ordering/test_default_relation_order.py b/tests/test_ordering/test_default_relation_order.py index 077646ff6..6e49bdea6 100644 --- a/tests/test_ordering/test_default_relation_order.py +++ b/tests/test_ordering/test_default_relation_order.py @@ -13,35 +13,31 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) - author: Optional[Author] = ormar.ForeignKey( - Author, orders_by=["name"], related_orders_by=["-year"] - ) + author: Optional[Author] = ormar.ForeignKey(Author, orders_by=["name"], related_orders_by=["-year"]) title: str = ormar.String(max_length=100) year: int = ormar.Integer(nullable=True) ranking: int = ormar.Integer(nullable=True) class Animal(ormar.Model): - class Meta(BaseMeta): - tablename = "animals" + ormar_config = base_ormar_config.copy(tablename="animals") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.String(max_length=200) @@ -49,8 +45,7 @@ class Meta(BaseMeta): class Human(ormar.Model): - class Meta(BaseMeta): - tablename = "humans" + ormar_config = base_ormar_config.copy(tablename="humans") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.Text(default="") @@ -84,12 +79,8 @@ async def test_default_orders_is_applied_from_reverse_relation(): async with database: tolkien = await Author(name="J.R.R. Tolkien").save() hobbit = await Book(author=tolkien, title="The Hobbit", year=1933).save() - silmarillion = await Book( - author=tolkien, title="The Silmarillion", year=1977 - ).save() - lotr = await Book( - author=tolkien, title="The Lord of the Rings", year=1955 - ).save() + silmarillion = await Book(author=tolkien, title="The Silmarillion", year=1977).save() + lotr = await Book(author=tolkien, title="The Lord of the Rings", year=1955).save() tolkien = await Author.objects.select_related("books").get() assert tolkien.books[2] == hobbit @@ -101,13 +92,9 @@ async def test_default_orders_is_applied_from_reverse_relation(): async def test_default_orders_is_applied_from_relation(): async with database: bret = await Author(name="Peter V. Bret").save() - tds = await Book( - author=bret, title="The Desert Spear", year=2010, ranking=9 - ).save() + tds = await Book(author=bret, title="The Desert Spear", year=2010, ranking=9).save() sanders = await Author(name="Brandon Sanderson").save() - twok = await Book( - author=sanders, title="The Way of Kings", year=2010, ranking=10 - ).save() + twok = await Book(author=sanders, title="The Way of Kings", year=2010, ranking=10).save() books = await Book.objects.order_by("year").select_related("author").all() assert books[0] == twok diff --git a/tests/test_ordering/test_default_through_relation_order.py b/tests/test_ordering/test_default_through_relation_order.py index f695426df..e05a7a553 100644 --- a/tests/test_ordering/test_default_through_relation_order.py +++ b/tests/test_ordering/test_default_through_relation_order.py @@ -14,14 +14,14 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Animal(ormar.Model): - class Meta(BaseMeta): - tablename = "animals" + ormar_config = base_ormar_config.copy(tablename="animals") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.Text(default="") @@ -29,8 +29,7 @@ class Meta(BaseMeta): class Link(ormar.Model): - class Meta(BaseMeta): - tablename = "link_table" + ormar_config = base_ormar_config.copy(tablename="link_table") id: UUID = ormar.UUID(primary_key=True, default=uuid4) animal_order: int = ormar.Integer(nullable=True) @@ -38,8 +37,7 @@ class Meta(BaseMeta): class Human(ormar.Model): - class Meta(BaseMeta): - tablename = "humans" + ormar_config = base_ormar_config.copy(tablename="humans") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.Text(default="") @@ -53,8 +51,7 @@ class Meta(BaseMeta): class Human2(ormar.Model): - class Meta(BaseMeta): - tablename = "humans2" + ormar_config = base_ormar_config.copy(tablename="humans2") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.Text(default="") @@ -82,9 +79,7 @@ async def test_ordering_by_through_fail(): await alice.load_all() -def _get_filtered_query( - sender: Type[Model], instance: Model, to_class: Type[Model] -) -> QuerySet: +def _get_filtered_query(sender: Type[Model], instance: Model, to_class: Type[Model]) -> QuerySet: """ Helper function. Gets the query filtered by the appropriate class name. @@ -95,12 +90,10 @@ def _get_filtered_query( return query -def _get_through_model_relations( - sender: Type[Model], instance: Model -) -> Tuple[Type[Model], Type[Model]]: +def _get_through_model_relations(sender: Type[Model], instance: Model) -> Tuple[Type[Model], Type[Model]]: relations = list(instance.extract_related_names()) - rel_one = sender.Meta.model_fields[relations[0]].to - rel_two = sender.Meta.model_fields[relations[1]].to + rel_one = sender.ormar_config.model_fields[relations[0]].to + rel_two = sender.ormar_config.model_fields[relations[1]].to return rel_one, rel_two @@ -158,9 +151,7 @@ async def _reorder_on_update( setattr(link, order, ind) else: setattr(link, order, ind + 1) - await sender.objects.bulk_update( - cast(List[Model], to_reorder), columns=[order] - ) + await sender.objects.bulk_update(cast(List[Model], to_reorder), columns=[order]) @pre_save(Link) @@ -171,18 +162,12 @@ async def order_link_on_insert(sender: Type[Model], instance: Model, **kwargs: A sender class, instance and have to accept **kwargs even if it's empty as of now. """ rel_one, rel_two = _get_through_model_relations(sender, instance) - await _populate_order_on_insert( - sender=sender, instance=instance, from_class=rel_one, to_class=rel_two - ) - await _populate_order_on_insert( - sender=sender, instance=instance, from_class=rel_two, to_class=rel_one - ) + await _populate_order_on_insert(sender=sender, instance=instance, from_class=rel_one, to_class=rel_two) + await _populate_order_on_insert(sender=sender, instance=instance, from_class=rel_two, to_class=rel_one) @pre_update(Link) -async def reorder_links_on_update( - sender: Type[ormar.Model], instance: ormar.Model, passed_args: Dict, **kwargs: Any -): +async def reorder_links_on_update(sender: Type[ormar.Model], instance: ormar.Model, passed_args: Dict, **kwargs: Any): """ Signal receiver registered on Link model, triggered every time before one is updated by calling update() on a model. Note that signal functions for pre_update signal @@ -223,7 +208,7 @@ async def reorder_links_on_remove( Note that if classes have many relations you need to check if current one is ordered """ - through_class = sender.Meta.model_fields[relation_name].through + through_class = sender.ormar_config.model_fields[relation_name].through through_instance = getattr(instance, through_class.get_name()) if not through_instance: parent_pk = instance.pk @@ -252,16 +237,12 @@ async def test_ordering_by_through_on_m2m_field(): async with database: def verify_order(instance, expected): - field_name = ( - "favoriteAnimals" if isinstance(instance, Human) else "favoriteHumans" - ) - order_field_name = ( - "animal_order" if isinstance(instance, Human) else "human_order" - ) + field_name = "favoriteAnimals" if isinstance(instance, Human) else "favoriteHumans" + order_field_name = "animal_order" if isinstance(instance, Human) else "human_order" assert [x.name for x in getattr(instance, field_name)] == expected - assert [ - getattr(x.link, order_field_name) for x in getattr(instance, field_name) - ] == [i for i in range(len(expected))] + assert [getattr(x.link, order_field_name) for x in getattr(instance, field_name)] == [ + i for i in range(len(expected)) + ] alice = await Human(name="Alice").save() bob = await Human(name="Bob").save() @@ -325,8 +306,6 @@ def verify_order(instance, expected): bob = await noodle.favoriteHumans.get(pk=bob.pk) assert bob.link.human_order == 1 - await noodle.favoriteHumans.remove( - await noodle.favoriteHumans.filter(link__human_order=2).get() - ) + await noodle.favoriteHumans.remove(await noodle.favoriteHumans.filter(link__human_order=2).get()) await noodle.load_all() verify_order(noodle, ["Alice", "Bob", "Zack"]) diff --git a/tests/test_ordering/test_proper_order_of_sorting_apply.py b/tests/test_ordering/test_proper_order_of_sorting_apply.py index 1a2186ba7..6ad597522 100644 --- a/tests/test_ordering/test_proper_order_of_sorting_apply.py +++ b/tests/test_ordering/test_proper_order_of_sorting_apply.py @@ -12,23 +12,23 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename = "authors") + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" - orders_by = ["-ranking"] + ormar_config = base_ormar_config.copy(tablename = "books", + order_by = ["-ranking"]) + id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey( diff --git a/tests/test_queries/test_adding_related.py b/tests/test_queries/test_adding_related.py index 271a13c0f..cfba88532 100644 --- a/tests/test_queries/test_adding_related.py +++ b/tests/test_queries/test_adding_related.py @@ -14,18 +14,20 @@ class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_queries/test_aggr_functions.py b/tests/test_queries/test_aggr_functions.py index ae41c634a..313bf7265 100644 --- a/tests/test_queries/test_aggr_functions.py +++ b/tests/test_queries/test_aggr_functions.py @@ -13,24 +13,24 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" - order_by = ["-name"] + ormar_config = base_ormar_config.copy(tablename = "authors", + order_by = ["-name"]) + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" - order_by = ["year", "-ranking"] + ormar_config = base_ormar_config.copy(tablename = "books", + order_by = ["year", "-ranking"]) + id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) diff --git a/tests/test_queries/test_deep_relations_select_all.py b/tests/test_queries/test_deep_relations_select_all.py index 948b81f2b..f53f8a575 100644 --- a/tests/test_queries/test_deep_relations_select_all.py +++ b/tests/test_queries/test_deep_relations_select_all.py @@ -11,10 +11,11 @@ class Chart(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "charts" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "charts", + database = database, + metadata = metadata, + ) chart_id = ormar.Integer(primary_key=True, autoincrement=True) name = ormar.String(max_length=200, unique=True, index=True) @@ -28,10 +29,11 @@ class Meta(ormar.ModelMeta): class Report(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "reports" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "reports", + database = database, + metadata = metadata, + ) report_id = ormar.Integer(primary_key=True, autoincrement=True) name = ormar.String(max_length=200, unique=True, index=True) @@ -40,10 +42,11 @@ class Meta(ormar.ModelMeta): class Language(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "languages" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "languages", + database = database, + metadata = metadata, + ) language_id = ormar.Integer(primary_key=True, autoincrement=True) code = ormar.String(max_length=5) @@ -51,20 +54,22 @@ class Meta(ormar.ModelMeta): class TranslationNode(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "translation_nodes" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "translation_nodes", + database = database, + metadata = metadata, + ) node_id = ormar.Integer(primary_key=True, autoincrement=True) node_type = ormar.String(max_length=200) class Translation(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "translations" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "translations", + database = database, + metadata = metadata, + ) translation_id = ormar.Integer(primary_key=True, autoincrement=True) node_id = ormar.ForeignKey(TranslationNode, related_name="translations") @@ -73,10 +78,11 @@ class Meta(ormar.ModelMeta): class Filter(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "filters" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "filters", + database = database, + metadata = metadata, + ) filter_id = ormar.Integer(primary_key=True, autoincrement=True) name = ormar.String(max_length=200, unique=True, index=True) @@ -90,10 +96,11 @@ class Meta(ormar.ModelMeta): class FilterValue(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "filter_values" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "filter_values", + database = database, + metadata = metadata, + ) value_id = ormar.Integer(primary_key=True, autoincrement=True) value = ormar.String(max_length=300) @@ -103,10 +110,11 @@ class Meta(ormar.ModelMeta): class FilterXReport(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "filters_x_reports" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "filters_x_reports", + database = database, + metadata = metadata, + ) filter_x_report_id = ormar.Integer(primary_key=True) filter = ormar.ForeignKey(Filter, name="filter_id", related_name="reports") @@ -117,10 +125,11 @@ class Meta(ormar.ModelMeta): class ChartXReport(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "charts_x_reports" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "charts_x_reports", + database = database, + metadata = metadata, + ) chart_x_report_id = ormar.Integer(primary_key=True) chart = ormar.ForeignKey(Chart, name="chart_id", related_name="reports") @@ -130,10 +139,11 @@ class Meta(ormar.ModelMeta): class ChartColumn(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "charts_columns" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "charts_columns", + database = database, + metadata = metadata, + ) column_id = ormar.Integer(primary_key=True, autoincrement=True) chart = ormar.ForeignKey(Chart, name="chart_id", related_name="columns") diff --git a/tests/test_queries/test_filter_groups.py b/tests/test_queries/test_filter_groups.py index 2e8a26b44..d318276ba 100644 --- a/tests/test_queries/test_filter_groups.py +++ b/tests/test_queries/test_filter_groups.py @@ -10,22 +10,20 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename = "authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy(tablename = "books") id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) diff --git a/tests/test_queries/test_indirect_relations_to_self.py b/tests/test_queries/test_indirect_relations_to_self.py index 4ca7adea1..d28d135be 100644 --- a/tests/test_queries/test_indirect_relations_to_self.py +++ b/tests/test_queries/test_indirect_relations_to_self.py @@ -12,10 +12,11 @@ class Node(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "node" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "node", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=120) @@ -24,10 +25,11 @@ class Meta(ormar.ModelMeta): class Edge(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "edge" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "edge", + database = database, + metadata = metadata, + ) id: str = ormar.String(primary_key=True, max_length=12) src_node: Node = ormar.ForeignKey(Node, related_name="next_edges") diff --git a/tests/test_queries/test_isnull_filter.py b/tests/test_queries/test_isnull_filter.py index 4c368e1c1..31cc8b0bc 100644 --- a/tests/test_queries/test_isnull_filter.py +++ b/tests/test_queries/test_isnull_filter.py @@ -11,22 +11,22 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename = "authors") + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy(tablename = "books") + id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -35,10 +35,11 @@ class Meta(BaseMeta): class JsonModel(ormar.Model): - class Meta(ormar.ModelMeta): - metadata = metadata - database = database - tablename = "jsons" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + tablename = "jsons", + ) id = ormar.Integer(primary_key=True) text_field = ormar.Text(nullable=True) diff --git a/tests/test_queries/test_nested_reverse_relations.py b/tests/test_queries/test_nested_reverse_relations.py index 914adc5a9..6938f2553 100644 --- a/tests/test_queries/test_nested_reverse_relations.py +++ b/tests/test_queries/test_nested_reverse_relations.py @@ -11,22 +11,22 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class DataSource(ormar.Model): - class Meta(BaseMeta): - tablename = "datasources" + ormar_config = base_ormar_config.copy(tablename = "datasources") + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, unique=True, index=True) class DataSourceTable(ormar.Model): - class Meta(BaseMeta): - tablename = "source_tables" + ormar_config = base_ormar_config.copy(tablename = "source_tables") + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, index=True) @@ -36,8 +36,7 @@ class Meta(BaseMeta): class DataSourceTableColumn(ormar.Model): - class Meta(BaseMeta): - tablename = "source_columns" + ormar_config = base_ormar_config.copy(tablename = "source_columns") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, index=True) diff --git a/tests/test_queries/test_non_relation_fields_not_merged.py b/tests/test_queries/test_non_relation_fields_not_merged.py index 38cda8766..c4732a1ce 100644 --- a/tests/test_queries/test_non_relation_fields_not_merged.py +++ b/tests/test_queries/test_non_relation_fields_not_merged.py @@ -11,22 +11,20 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Chart(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename = "authors") id: int = ormar.Integer(primary_key=True) datasets = ormar.JSON() class Config(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy(tablename = "books") id: int = ormar.Integer(primary_key=True) chart: Optional[Chart] = ormar.ForeignKey(Chart) diff --git a/tests/test_queries/test_or_filters.py b/tests/test_queries/test_or_filters.py index 370c84807..b839d6289 100644 --- a/tests/test_queries/test_or_filters.py +++ b/tests/test_queries/test_or_filters.py @@ -12,22 +12,21 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -124,10 +123,7 @@ async def test_or_filters(): ( ( (Book.year > 1960) & (Book.author.name == "J.R.R. Tolkien") - | ( - (Book.year < 2000) - & (Book.author.name == "Andrzej Sapkowski") - ) + | ((Book.year < 2000) & (Book.author.name == "Andrzej Sapkowski")) ) & (Book.title.startswith("The")) ) @@ -183,9 +179,7 @@ async def test_or_filters(): .all() ) assert len(books) == 3 - assert not any( - [x.title in ["The Tower of Fools", "The Lord of the Rings"] for x in books] - ) + assert not any([x.title in ["The Tower of Fools", "The Lord of the Rings"] for x in books]) books = ( await Book.objects.select_related("author") @@ -233,24 +227,16 @@ async def test_or_filters(): with pytest.raises(QueryDefinitionError): await Book.objects.select_related("author").filter("wrong").all() - books = await tolkien.books.filter( - ormar.or_(year__lt=1940, year__gt=1960) - ).all() + books = await tolkien.books.filter(ormar.or_(year__lt=1940, year__gt=1960)).all() assert len(books) == 2 books = await tolkien.books.filter( - ormar.and_( - ormar.or_(year__lt=1940, year__gt=1960), title__icontains="hobbit" - ) + ormar.and_(ormar.or_(year__lt=1940, year__gt=1960), title__icontains="hobbit") ).all() assert len(books) == 1 assert tolkien.books[0].title == "The Hobbit" - books = ( - await Book.objects.select_related("author") - .filter(ormar.or_(author__name="J.R.R. Tolkien")) - .all() - ) + books = await Book.objects.select_related("author").filter(ormar.or_(author__name="J.R.R. Tolkien")).all() assert len(books) == 3 books = ( diff --git a/tests/test_queries/test_order_by.py b/tests/test_queries/test_order_by.py index d32cf685c..e4f90bec5 100644 --- a/tests/test_queries/test_order_by.py +++ b/tests/test_queries/test_order_by.py @@ -12,10 +12,11 @@ class Song(ormar.Model): - class Meta: - tablename = "songs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "songs", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -23,30 +24,33 @@ class Meta: class Owner(ormar.Model): - class Meta: - tablename = "owners" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "owners", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class AliasNested(ormar.Model): - class Meta: - tablename = "aliases_nested" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "aliases_nested", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(name="alias_id", primary_key=True) name: str = ormar.String(name="alias_name", max_length=100) class AliasTest(ormar.Model): - class Meta: - tablename = "aliases" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "aliases", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(name="alias_id", primary_key=True) name: str = ormar.String(name="alias_name", max_length=100) @@ -54,10 +58,11 @@ class Meta: class Toy(ormar.Model): - class Meta: - tablename = "toys" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "toys", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -65,20 +70,22 @@ class Meta: class Factory(ormar.Model): - class Meta: - tablename = "factories" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "factories", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Car(ormar.Model): - class Meta: - tablename = "cars" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "cars", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -86,10 +93,11 @@ class Meta: class User(ormar.Model): - class Meta: - tablename = "users" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "users", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_queries/test_pagination.py b/tests/test_queries/test_pagination.py index 9650736a0..7a1dfec21 100644 --- a/tests/test_queries/test_pagination.py +++ b/tests/test_queries/test_pagination.py @@ -3,7 +3,6 @@ import sqlalchemy import ormar -from ormar import ModelMeta from ormar.exceptions import QueryDefinitionError from tests.settings import DATABASE_URL @@ -11,27 +10,25 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class Car(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class UsersCar(ormar.Model): - class Meta(BaseMeta): - tablename = "cars_x_users" + ormar_config = base_ormar_config.copy(tablename="cars_x_users") class User(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_queries/test_queryproxy_on_m2m_models.py b/tests/test_queries/test_queryproxy_on_m2m_models.py index 17d9233be..430dae7f9 100644 --- a/tests/test_queries/test_queryproxy_on_m2m_models.py +++ b/tests/test_queries/test_queryproxy_on_m2m_models.py @@ -14,20 +14,22 @@ class Subject(ormar.Model): - class Meta: - tablename = "subjects" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "subjects", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=80) class Author(ormar.Model): - class Meta: - tablename = "authors" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "authors", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -35,10 +37,11 @@ class Meta: class Category(ormar.Model): - class Meta: - tablename = "categories" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "categories", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) @@ -47,17 +50,19 @@ class Meta: class PostCategory(ormar.Model): - class Meta: - tablename = "posts_categories" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "posts_categories", + database = database, + metadata = metadata, + ) class Post(ormar.Model): - class Meta: - tablename = "posts" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "posts", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) diff --git a/tests/test_queries/test_queryset_level_methods.py b/tests/test_queries/test_queryset_level_methods.py index e0f4f8837..76bfe6bfa 100644 --- a/tests/test_queries/test_queryset_level_methods.py +++ b/tests/test_queries/test_queryset_level_methods.py @@ -26,10 +26,11 @@ class MySize(Enum): class Book(ormar.Model): - class Meta: - tablename = "books" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "books", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -42,10 +43,11 @@ class Meta: class ToDo(ormar.Model): - class Meta: - tablename = "todos" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "todos", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) text: str = ormar.String(max_length=500) @@ -55,20 +57,22 @@ class Meta: class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "categories", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=500) class Note(ormar.Model): - class Meta: - tablename = "notes" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "notes", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) text: str = ormar.String(max_length=500) @@ -76,10 +80,11 @@ class Meta: class ItemConfig(ormar.Model): - class Meta(ormar.ModelMeta): - metadata = metadata - database = database - tablename = "item_config" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + tablename = "item_config", + ) id: Optional[int] = ormar.Integer(primary_key=True) item_id: str = ormar.String(max_length=32, index=True) @@ -97,21 +102,23 @@ async def first_or_404(self, *args, **kwargs): class Customer(ormar.Model): - class Meta: - metadata = metadata - database = database - tablename = "customer" - queryset_class = QuerySetCls + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + tablename = "customer", + queryset_class = QuerySetCls, + ) id: Optional[int] = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=32) class JsonTestModel(ormar.Model): - class Meta(ormar.ModelMeta): - metadata = metadata - database = database - tablename = "test_model" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + tablename = "test_model", + ) id: int = ormar.Integer(primary_key=True) json_field: Json = ormar.JSON() @@ -308,7 +315,7 @@ async def test_bulk_create_json_field(): assert test_model_1.json_field == test_model_2.json_field # True # try to query the json field - table = JsonTestModel.Meta.table + table = JsonTestModel.ormar_config.table query = table.select().where(table.c.json_field["a"].as_integer() == 1) res = [ JsonTestModel.from_row(record, source_model=JsonTestModel) @@ -469,7 +476,7 @@ async def test_bulk_operations_with_json(): items = await ItemConfig.objects.filter(ItemConfig.id > 1).all() assert all(x.pairs == {"b": 2} for x in items) - table = ItemConfig.Meta.table + table = ItemConfig.ormar_config.table query = table.select().where(table.c.pairs["b"].as_integer() == 2) res = [ ItemConfig.from_row(record, source_model=ItemConfig) diff --git a/tests/test_queries/test_quoting_table_names_in_on_join_clause.py b/tests/test_queries/test_quoting_table_names_in_on_join_clause.py index 9421f01ec..c78cc21bc 100644 --- a/tests/test_queries/test_quoting_table_names_in_on_join_clause.py +++ b/tests/test_queries/test_quoting_table_names_in_on_join_clause.py @@ -16,10 +16,11 @@ class Team(ormar.Model): - class Meta: - tablename: str = "team" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "team", + database = database, + metadata = metadata, + ) id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) name = ormar.Text(nullable=True) @@ -29,10 +30,11 @@ class Meta: class User(ormar.Model): - class Meta: - tablename: str = "user" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "user", + database = database, + metadata = metadata, + ) id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) client_user_id = ormar.Text() @@ -41,10 +43,11 @@ class Meta: class Order(ormar.Model): - class Meta: - tablename: str = "order" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "order", + database = database, + metadata = metadata, + ) id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) user: Optional[Union[User, Dict]] = ormar.ForeignKey(User) diff --git a/tests/test_queries/test_reserved_sql_keywords_escaped.py b/tests/test_queries/test_reserved_sql_keywords_escaped.py index b881b3b39..68c82741e 100644 --- a/tests/test_queries/test_reserved_sql_keywords_escaped.py +++ b/tests/test_queries/test_reserved_sql_keywords_escaped.py @@ -10,14 +10,13 @@ metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - +base_ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, +) class User(ormar.Model): - class Meta(BaseMeta): - tablename = "user" + ormar_config = base_ormar_config.copy(tablename = "user") id: int = ormar.Integer(primary_key=True, autoincrement=True, nullable=False) user: str = ormar.String( @@ -33,8 +32,7 @@ class Meta(BaseMeta): class Task(ormar.Model): - class Meta(BaseMeta): - tablename = "task" + ormar_config = base_ormar_config.copy(tablename = "task") id: int = ormar.Integer(primary_key=True, autoincrement=True, nullable=False) from_: str = ormar.String(name="from", nullable=True, max_length=200) diff --git a/tests/test_queries/test_reverse_fk_queryset.py b/tests/test_queries/test_reverse_fk_queryset.py index 25f54a0cc..5ed881074 100644 --- a/tests/test_queries/test_reverse_fk_queryset.py +++ b/tests/test_queries/test_reverse_fk_queryset.py @@ -13,10 +13,11 @@ class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "albums", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True, name="album_id") name: str = ormar.String(max_length=100) @@ -24,20 +25,22 @@ class Meta: class Writer(ormar.Model): - class Meta: - tablename = "writers" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "writers", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True, name="writer_id") name: str = ormar.String(max_length=100) class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "tracks", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album, name="album_id") diff --git a/tests/test_queries/test_selecting_subset_of_columns.py b/tests/test_queries/test_selecting_subset_of_columns.py index da5c000ee..14f5f15e1 100644 --- a/tests/test_queries/test_selecting_subset_of_columns.py +++ b/tests/test_queries/test_selecting_subset_of_columns.py @@ -16,10 +16,11 @@ class NickNames(ormar.Model): - class Meta: - tablename = "nicks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "nicks", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -27,17 +28,19 @@ class Meta: class NicksHq(ormar.Model): - class Meta: - tablename = "nicks_x_hq" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "nicks_x_hq", + metadata = metadata, + database = database, + ) class HQ(ormar.Model): - class Meta: - tablename = "hqs" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "hqs", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -45,10 +48,11 @@ class Meta: class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "companies", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -57,10 +61,11 @@ class Meta: class Car(ormar.Model): - class Meta: - tablename = "cars" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "cars", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) manufacturer: Optional[Company] = ormar.ForeignKey(Company) @@ -226,7 +231,7 @@ async def test_selecting_subset(): assert all_cars_dummy[0].manufacturer.founded is None - with pytest.raises(pydantic.error_wrappers.ValidationError): + with pytest.raises(pydantic.ValidationError): # cannot exclude mandatory model columns - company__name in this example await Car.objects.select_related("manufacturer").fields( ["id", "name", "manufacturer__founded"] diff --git a/tests/test_queries/test_values_and_values_list.py b/tests/test_queries/test_values_and_values_list.py index ff9f3712c..222d9cc2c 100644 --- a/tests/test_queries/test_values_and_values_list.py +++ b/tests/test_queries/test_values_and_values_list.py @@ -21,16 +21,14 @@ class User(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Role(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -38,8 +36,7 @@ class Meta(BaseMeta): class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy( tablename = "categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) @@ -48,8 +45,7 @@ class Meta(BaseMeta): class Post(ormar.Model): - class Meta(BaseMeta): - tablename = "posts" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200) diff --git a/tests/test_relations/test_cascades.py b/tests/test_relations/test_cascades.py index 49c4a031f..d2c5fdc02 100644 --- a/tests/test_relations/test_cascades.py +++ b/tests/test_relations/test_cascades.py @@ -13,29 +13,32 @@ class Band(ormar.Model): - class Meta: - tablename = "bands" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="bands", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class ArtistsBands(ormar.Model): - class Meta: - tablename = "artists_x_bands" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="artists_x_bands", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) class Artist(ormar.Model): - class Meta: - tablename = "artists" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="artists", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -43,10 +46,11 @@ class Meta: class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="albums", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -54,10 +58,11 @@ class Meta: class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="tracks", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album, ondelete="CASCADE") diff --git a/tests/test_relations/test_customizing_through_model_relation_names.py b/tests/test_relations/test_customizing_through_model_relation_names.py index ff99065a1..62ec66c4f 100644 --- a/tests/test_relations/test_customizing_through_model_relation_names.py +++ b/tests/test_relations/test_customizing_through_model_relation_names.py @@ -10,18 +10,20 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) course_name: str = ormar.String(max_length=100) class Student(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -42,7 +44,7 @@ def create_test_database(): def test_tables_columns(): - through_meta = Student.Meta.model_fields["courses"].through.Meta + through_meta = Student.ormar_config.model_fields["courses"].through.ormar_config assert "course_id" in through_meta.table.c assert "student_id" in through_meta.table.c assert "course_id" in through_meta.model_fields @@ -70,15 +72,9 @@ async def test_working_with_changed_through_names(): student = await course_check.students.get(name="Jack") assert student.name == "Jack" - students = await Student.objects.select_related("courses").all( - courses__course_name="basic1" - ) + students = await Student.objects.select_related("courses").all(courses__course_name="basic1") assert len(students) == 2 - course_check = ( - await Course.objects.select_related("students") - .order_by("students__name") - .get() - ) + course_check = await Course.objects.select_related("students").order_by("students__name").get() assert course_check.students[0].name == "Abi" assert course_check.students[1].name == "Jack" diff --git a/tests/test_relations/test_database_fk_creation.py b/tests/test_relations/test_database_fk_creation.py index 7f8e3488c..331e66a4c 100644 --- a/tests/test_relations/test_database_fk_creation.py +++ b/tests/test_relations/test_database_fk_creation.py @@ -14,20 +14,22 @@ class Artist(ormar.Model): - class Meta: - tablename = "artists" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="artists", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename="albums", + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -35,18 +37,20 @@ class Meta: class A(ormar.Model): - class Meta: - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=64, nullalbe=False) class B(ormar.Model): - class Meta: - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=64, nullalbe=False) @@ -54,9 +58,10 @@ class Meta: class C(ormar.Model): - class Meta: - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + metadata=metadata, + database=database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=64, nullalbe=False) diff --git a/tests/test_relations/test_foreign_keys.py b/tests/test_relations/test_foreign_keys.py index e3412ed9f..7caa5aaf1 100644 --- a/tests/test_relations/test_foreign_keys.py +++ b/tests/test_relations/test_foreign_keys.py @@ -13,10 +13,11 @@ class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "albums", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -24,10 +25,11 @@ class Meta: class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "tracks", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -38,10 +40,11 @@ class Meta: class Cover(ormar.Model): - class Meta: - tablename = "covers" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "covers", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album, related_name="cover_pictures") @@ -49,20 +52,22 @@ class Meta: class Organisation(ormar.Model): - class Meta: - tablename = "org" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "org", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) ident: str = ormar.String(max_length=100, choices=["ACME Ltd", "Other ltd"]) class Team(ormar.Model): - class Meta: - tablename = "teams" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "teams", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) org: Optional[Organisation] = ormar.ForeignKey(Organisation) @@ -70,10 +75,11 @@ class Meta: class Member(ormar.Model): - class Meta: - tablename = "members" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "members", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) team: Optional[Team] = ormar.ForeignKey(Team) @@ -301,14 +307,6 @@ async def test_multiple_fk(): assert member.team.org.ident == "ACME Ltd" -@pytest.mark.asyncio -async def test_wrong_choices(): - async with database: - async with database.transaction(force_rollback=True): - with pytest.raises(ValueError): - await Organisation.objects.create(ident="Test 1") - - @pytest.mark.asyncio async def test_pk_filter(): async with database: diff --git a/tests/test_relations/test_m2m_through_fields.py b/tests/test_relations/test_m2m_through_fields.py index c56b1ce3a..61390c720 100644 --- a/tests/test_relations/test_m2m_through_fields.py +++ b/tests/test_relations/test_m2m_through_fields.py @@ -3,7 +3,7 @@ import databases import pytest import sqlalchemy -from pydantic.typing import ForwardRef +from typing import ForwardRef import ormar from tests.settings import DATABASE_URL @@ -19,16 +19,16 @@ class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename = "categories") + id = ormar.Integer(primary_key=True) name = ormar.String(max_length=40) class PostCategory(ormar.Model): - class Meta(BaseMeta): - tablename = "posts_x_categories" + ormar_config = base_ormar_config.copy(tablename = "posts_x_categories") + id: int = ormar.Integer(primary_key=True) sort_order: int = ormar.Integer(nullable=True) @@ -36,16 +36,14 @@ class Meta(BaseMeta): class Blog(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -63,16 +61,15 @@ def create_test_database(): class PostCategory2(ormar.Model): - class Meta(BaseMeta): - tablename = "posts_x_categories2" + ormar_config = base_ormar_config.copy(tablename = "posts_x_categories2") + id: int = ormar.Integer(primary_key=True) sort_order: int = ormar.Integer(nullable=True) class Post2(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -82,10 +79,10 @@ class Meta(BaseMeta): @pytest.mark.asyncio async def test_forward_ref_is_updated(): async with database: - assert Post2.Meta.requires_ref_update + assert Post2.ormar_config.requires_ref_update Post2.update_forward_refs() - assert Post2.Meta.model_fields["postcategory2"].to == PostCategory2 + assert Post2.ormar_config.model_fields["postcategory2"].to == PostCategory2 @pytest.mark.asyncio diff --git a/tests/test_relations/test_many_to_many.py b/tests/test_relations/test_many_to_many.py index 120bc1f3a..251023c0e 100644 --- a/tests/test_relations/test_many_to_many.py +++ b/tests/test_relations/test_many_to_many.py @@ -15,10 +15,11 @@ class Author(ormar.Model): - class Meta: - tablename = "authors" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="authors", + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -26,20 +27,22 @@ class Meta: class Category(ormar.Model): - class Meta: - tablename = "categories" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="categories", + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - class Meta: - tablename = "posts" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="posts", + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -66,7 +69,7 @@ async def create_test_database(): async def cleanup(): yield async with database: - PostCategory = Post.Meta.model_fields["categories"].through + PostCategory = Post.ormar_config.model_fields["categories"].through await PostCategory.objects.delete(each=True) await Post.objects.delete(each=True) await Category.objects.delete(each=True) @@ -148,9 +151,7 @@ async def test_quering_of_the_m2m_models(cleanup): category = await Category.objects.filter(posts__author=guido).get() assert category == news # or: - category2 = await Category.objects.filter( - posts__author__first_name="Guido" - ).get() + category2 = await Category.objects.filter(posts__author__first_name="Guido").get() assert category2 == news diff --git a/tests/test_relations/test_postgress_select_related_with_limit.py b/tests/test_relations/test_postgress_select_related_with_limit.py index 0369fa41c..05dd41f34 100644 --- a/tests/test_relations/test_postgress_select_related_with_limit.py +++ b/tests/test_relations/test_postgress_select_related_with_limit.py @@ -28,9 +28,10 @@ class Level(Enum): STAFF = "1" -class MainMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, +) class User(PrimaryKeyMixin, ormar.Model): @@ -46,9 +47,9 @@ class User(PrimaryKeyMixin, ormar.Model): fullname: Optional[str] = ormar.String(max_length=64, nullable=True, default=None) is_active: bool = ormar.Boolean(index=True, nullable=False, default=True) - class Meta(MainMeta): - orders_by = ["-is_active", "-level"] - + ormar_config = base_ormar_config.copy( + order_by = ["-is_active", "-level"] + ) class Task(PrimaryKeyMixin, ormar.Model): """Task Model Class to Implement Method for Operations of Task Entity""" @@ -60,11 +61,12 @@ class Task(PrimaryKeyMixin, ormar.Model): is_halted: bool = ormar.Boolean(index=True, nullable=False, default=True) user: User = ormar.ForeignKey(to=User) - class Meta(MainMeta): - orders_by = ["-end_date", "-start_date"] + ormar_config = base_ormar_config.copy( + order_by = ["-end_date", "-start_date"], constraints = [ ormar.UniqueColumns("user", "name"), ] + ) @pytest.fixture(autouse=True, scope="module") diff --git a/tests/test_relations/test_prefetch_related.py b/tests/test_relations/test_prefetch_related.py index 9347c3af6..1b9859500 100644 --- a/tests/test_relations/test_prefetch_related.py +++ b/tests/test_relations/test_prefetch_related.py @@ -12,20 +12,22 @@ class RandomSet(ormar.Model): - class Meta: - tablename = "randoms" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "randoms", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(name="random_id", primary_key=True) name: str = ormar.String(max_length=100) class Tonation(ormar.Model): - class Meta: - tablename = "tonations" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "tonations", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(name="tonation_name", max_length=100) @@ -33,20 +35,22 @@ class Meta: class Division(ormar.Model): - class Meta: - tablename = "divisions" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "divisions", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(name="division_id", primary_key=True) name: str = ormar.String(max_length=100, nullable=True) class Shop(ormar.Model): - class Meta: - tablename = "shops" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "shops", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=True) @@ -54,17 +58,19 @@ class Meta: class AlbumShops(ormar.Model): - class Meta: - tablename = "albums_x_shops" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "albums_x_shops", + metadata = metadata, + database = database, + ) class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "albums", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=True) @@ -72,10 +78,11 @@ class Meta: class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "tracks", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(name="track_id", primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -85,10 +92,11 @@ class Meta: class Cover(ormar.Model): - class Meta: - tablename = "covers" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "covers", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey( diff --git a/tests/test_relations/test_prefetch_related_multiple_models_relation.py b/tests/test_relations/test_prefetch_related_multiple_models_relation.py index e0e52f951..2750b00e6 100644 --- a/tests/test_relations/test_prefetch_related_multiple_models_relation.py +++ b/tests/test_relations/test_prefetch_related_multiple_models_relation.py @@ -14,29 +14,32 @@ class User(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "test_users" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + tablename = "test_users", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) class Signup(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "test_signup" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + tablename = "test_signup", + ) id: int = ormar.Integer(primary_key=True) class Session(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "test_sessions" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + tablename = "test_sessions", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) diff --git a/tests/test_relations/test_python_style_relations.py b/tests/test_relations/test_python_style_relations.py index 50738efba..fb5786a85 100644 --- a/tests/test_relations/test_python_style_relations.py +++ b/tests/test_relations/test_python_style_relations.py @@ -13,10 +13,11 @@ class Author(ormar.Model): - class Meta: - tablename = "authors" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "authors", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -24,20 +25,22 @@ class Meta: class Category(ormar.Model): - class Meta: - tablename = "categories" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "categories", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - class Meta: - tablename = "posts" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "posts", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -57,7 +60,7 @@ def create_test_database(): async def cleanup(): yield async with database: - PostCategory = Post.Meta.model_fields["categories"].through + PostCategory = Post.ormar_config.model_fields["categories"].through await PostCategory.objects.delete(each=True) await Post.objects.delete(each=True) await Category.objects.delete(each=True) diff --git a/tests/test_relations/test_relations_default_exception.py b/tests/test_relations/test_relations_default_exception.py index 1573e138c..5b1104cf6 100644 --- a/tests/test_relations/test_relations_default_exception.py +++ b/tests/test_relations/test_relations_default_exception.py @@ -14,10 +14,11 @@ class Author(ormar.Model): - class Meta: - tablename = "authors" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "authors", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -25,10 +26,11 @@ class Meta: class Category(ormar.Model): - class Meta: - tablename = "categories" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "categories", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) @@ -38,10 +40,11 @@ def test_fk_error(): with pytest.raises(ModelDefinitionError): class Post(ormar.Model): - class Meta: - tablename = "posts" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "posts", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -53,10 +56,11 @@ def test_m2m_error(): with pytest.raises(ModelDefinitionError): class Post(ormar.Model): - class Meta: - tablename = "posts" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename = "posts", + database = database, + metadata = metadata, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) diff --git a/tests/test_relations/test_saving_related.py b/tests/test_relations/test_saving_related.py index 388e29060..8b6c23c60 100644 --- a/tests/test_relations/test_saving_related.py +++ b/tests/test_relations/test_saving_related.py @@ -14,10 +14,11 @@ class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "categories", + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -25,10 +26,11 @@ class Meta: class Workshop(ormar.Model): - class Meta: - tablename = "workshops" - metadata = metadata - database = db + ormar_config = ormar.OrmarConfig( + tablename = "workshops", + metadata = metadata, + database = db, + ) id: int = ormar.Integer(primary_key=True) topic: str = ormar.String(max_length=255, index=True) diff --git a/tests/test_relations/test_select_related_with_limit.py b/tests/test_relations/test_select_related_with_limit.py index 47aa808ae..221749148 100644 --- a/tests/test_relations/test_select_related_with_limit.py +++ b/tests/test_relations/test_select_related_with_limit.py @@ -14,29 +14,32 @@ class Keyword(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "keywords" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + tablename = "keywords", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) class KeywordPrimaryModel(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "primary_models_keywords" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + tablename = "primary_models_keywords", + ) id: int = ormar.Integer(primary_key=True) class PrimaryModel(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "primary_models" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + tablename = "primary_models", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) @@ -48,10 +51,11 @@ class Meta: class SecondaryModel(ormar.Model): - class Meta: - metadata = metadata - database = db - tablename = "secondary_models" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = db, + tablename = "secondary_models", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py b/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py index 85cdea605..4cf1051fc 100644 --- a/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py +++ b/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py @@ -15,14 +15,14 @@ metadata = sqlalchemy.MetaData() -class MainMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, +) class Role(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = base_ormar_config.copy() name: str = ormar.String(primary_key=True, max_length=1000) order: int = ormar.Integer(default=0, name="sort_order") @@ -30,20 +30,17 @@ class Meta(MainMeta): class Company(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = base_ormar_config.copy() name: str = ormar.String(primary_key=True, max_length=1000) class UserRoleCompany(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = base_ormar_config.copy() class User(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = base_ormar_config.copy() registrationnumber: str = ormar.String(primary_key=True, max_length=1000) company: Company = ormar.ForeignKey(Company) @@ -68,8 +65,7 @@ def test_wrong_model(): with pytest.raises(ModelDefinitionError): class User(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = base_ormar_config.copy() registrationnumber: str = ormar.Text(primary_key=True) company: Company = ormar.ForeignKey(Company) diff --git a/tests/test_relations/test_selecting_proper_table_prefix.py b/tests/test_relations/test_selecting_proper_table_prefix.py index c4e93ec79..056abffe4 100644 --- a/tests/test_relations/test_selecting_proper_table_prefix.py +++ b/tests/test_relations/test_selecting_proper_table_prefix.py @@ -13,29 +13,32 @@ class User(ormar.Model): - class Meta: - metadata = metadata - database = database - tablename = "test_users" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + tablename = "test_users", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) class Signup(ormar.Model): - class Meta: - metadata = metadata - database = database - tablename = "test_signup" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + tablename = "test_signup", + ) id: int = ormar.Integer(primary_key=True) class Session(ormar.Model): - class Meta: - metadata = metadata - database = database - tablename = "test_sessions" + ormar_config = ormar.OrmarConfig( + metadata = metadata, + database = database, + tablename = "test_sessions", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) diff --git a/tests/test_relations/test_skipping_reverse.py b/tests/test_relations/test_skipping_reverse.py index bec61aa13..033a3a833 100644 --- a/tests/test_relations/test_skipping_reverse.py +++ b/tests/test_relations/test_skipping_reverse.py @@ -19,8 +19,7 @@ class Author(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -28,16 +27,14 @@ class Meta(BaseMeta): class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename = "categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -57,7 +54,7 @@ def create_test_database(): async def cleanup(): yield async with database: - PostCategory = Post.Meta.model_fields["categories"].through + PostCategory = Post.ormar_config.model_fields["categories"].through await PostCategory.objects.delete(each=True) await Post.objects.delete(each=True) await Category.objects.delete(each=True) diff --git a/tests/test_relations/test_through_relations_fail.py b/tests/test_relations/test_through_relations_fail.py index 472a8a142..454462b98 100644 --- a/tests/test_relations/test_through_relations_fail.py +++ b/tests/test_relations/test_through_relations_fail.py @@ -13,27 +13,26 @@ def test_through_with_relation_fails(): - class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata + base_ormar_config = ormar.OrmarConfig( + database = database, + metadata = metadata, + ) class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename = "categories") id = ormar.Integer(primary_key=True) name = ormar.String(max_length=40) class Blog(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) class PostCategory(ormar.Model): - class Meta(BaseMeta): - tablename = "posts_x_categories" + ormar_config = base_ormar_config.copy(tablename = "posts_x_categories") + id: int = ormar.Integer(primary_key=True) sort_order: int = ormar.Integer(nullable=True) @@ -43,8 +42,7 @@ class Meta(BaseMeta): with pytest.raises(ModelDefinitionError): class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) diff --git a/tests/test_relations/test_weakref_checking.py b/tests/test_relations/test_weakref_checking.py index dded7fc65..512a42f41 100644 --- a/tests/test_relations/test_weakref_checking.py +++ b/tests/test_relations/test_weakref_checking.py @@ -13,20 +13,22 @@ class Band(ormar.Model): - class Meta: - tablename = "bands" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "bands", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Artist(ormar.Model): - class Meta: - tablename = "artists" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "artists", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_signals/test_signals.py b/tests/test_signals/test_signals.py index 47666fafa..5622c5ae8 100644 --- a/tests/test_signals/test_signals.py +++ b/tests/test_signals/test_signals.py @@ -25,10 +25,11 @@ class AuditLog(ormar.Model): - class Meta: - tablename = "audits" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "audits", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) event_type: str = ormar.String(max_length=100) @@ -36,20 +37,22 @@ class Meta: class Cover(ormar.Model): - class Meta: - tablename = "covers" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "covers", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=100) class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "albums", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -364,7 +367,7 @@ async def after_update(sender, instance, **kwargs): instance.is_best_seller = False await instance.update() - Album.Meta.signals.custom.connect(after_update) + Album.ormar_config.signals.custom.connect(after_update) # here album.play_count ans is_best_seller get default values album = await Album.objects.create(name="Venice") @@ -379,13 +382,13 @@ async def after_update(sender, instance, **kwargs): album.play_count = 60 await album.update() assert not album.is_best_seller - await Album.Meta.signals.custom.send(sender=Album, instance=album) + await Album.ormar_config.signals.custom.send(sender=Album, instance=album) assert album.is_best_seller album.play_count = 30 await album.update() assert album.is_best_seller - await Album.Meta.signals.custom.send(sender=Album, instance=album) + await Album.ormar_config.signals.custom.send(sender=Album, instance=album) assert not album.is_best_seller - Album.Meta.signals.custom.disconnect(after_update) + Album.ormar_config.signals.custom.disconnect(after_update) diff --git a/tests/test_signals/test_signals_for_relations.py b/tests/test_signals/test_signals_for_relations.py index 8d7599f36..1fd67d812 100644 --- a/tests/test_signals/test_signals_for_relations.py +++ b/tests/test_signals/test_signals_for_relations.py @@ -20,10 +20,11 @@ class AuditLog(ormar.Model): - class Meta: - tablename = "audits" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "audits", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) event_type: str = ormar.String(max_length=100) @@ -31,30 +32,33 @@ class Meta: class Cover(ormar.Model): - class Meta: - tablename = "covers" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "covers", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=100) class Artist(ormar.Model): - class Meta: - tablename = "artists" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "artists", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(name="artist_id", primary_key=True) name: str = ormar.String(name="fname", max_length=100) class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "albums", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=100) diff --git a/tests/test_utils/test_queryset_utils.py b/tests/test_utils/test_queryset_utils.py index 02ca17200..bd52b00a4 100644 --- a/tests/test_utils/test_queryset_utils.py +++ b/tests/test_utils/test_queryset_utils.py @@ -178,10 +178,11 @@ def test_subtracting_with_set_and_dict(): class SortModel(ormar.Model): - class Meta: - tablename = "sorts" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + tablename = "sorts", + metadata = metadata, + database = database, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) From ffdbf4a3bc983b7ae8f104c4c9eb90c41b132e91 Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 14 Dec 2023 15:08:37 +0100 Subject: [PATCH 05/95] WIP fix part of the getting pydantic tests as types of fields are now kept in core schema and not on fieldsinfo --- ormar/fields/foreign_key.py | 5 +- ormar/fields/many_to_many.py | 9 +- ormar/models/mixins/pydantic_mixin.py | 4 +- ormar/models/newbasemodel.py | 3 +- tests/test_deferred/test_forward_refs.py | 6 +- .../test_geting_pydantic_models.py | 209 ++++++++++-------- 6 files changed, 133 insertions(+), 103 deletions(-) diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index 6973fb84a..c58518f35 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -15,7 +15,6 @@ overload, ) -from pydantic.v1.typing import evaluate_forwardref import ormar # noqa I101 import sqlalchemy @@ -368,9 +367,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = evaluate_forwardref( - self.to, globalns, localns or None # type: ignore - ) + self.to = self.to._evaluate(globalns, localns, set()) ( self.__type__, self.constraints, diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index b22c683b0..73cc4f1d5 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -224,18 +224,15 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = evaluate_forwardref( - self.to, globalns, localns or None # type: ignore - ) + self.to = self.to._evaluate(globalns, localns, set()) (self.__type__, self.column_type) = populate_m2m_params_based_on_to_model( to=self.to, nullable=self.nullable ) if self.through.__class__ == ForwardRef: - self.through = evaluate_forwardref( - self.through, globalns, localns or None # type: ignore - ) + self.through = self.through._evaluate(globalns, localns, set()) + forbid_through_relations(self.through) def get_relation_name(self) -> str: diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index 995aaa673..6f222c851 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -15,7 +15,7 @@ ) import pydantic -from pydantic.fields import Field +from pydantic.fields import Field, FieldInfo from ormar.models.mixins.relation_mixin import RelationMixin # noqa: I100, I202 from ormar.queryset.utils import translate_list_to_dict @@ -117,6 +117,8 @@ def _determine_pydantic_field_type( ) if field.is_multi or field.virtual: target = List[target] # type: ignore + if field.nullable: + defaults[name] = None elif not field.is_relation: defaults[name] = cls.model_fields[name].default target = field.__type__ diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index e8e6855db..2abfeaed7 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -567,7 +567,8 @@ def update_forward_refs(cls, **localns: Any) -> None: register_relation_in_alias_manager(field=field) update_column_definition(model=cls, field=field) populate_meta_sqlalchemy_table_if_required(meta=cls.ormar_config) - super().update_forward_refs(**localns) + # super().update_forward_refs(**localns) + cls.model_rebuild(force=True) cls.ormar_config.requires_ref_update = False @staticmethod diff --git a/tests/test_deferred/test_forward_refs.py b/tests/test_deferred/test_forward_refs.py index 628755446..b31487446 100644 --- a/tests/test_deferred/test_forward_refs.py +++ b/tests/test_deferred/test_forward_refs.py @@ -1,5 +1,5 @@ # type: ignore -from typing import List +from typing import List, Optional import databases import pytest @@ -193,8 +193,8 @@ def test_proper_field_init(): assert "supervisor" in Person.ormar_config.model_fields assert Person.ormar_config.model_fields["supervisor"].to == Person - assert "supervisor" in Person.__fields__ - assert Person.__fields__["supervisor"].type_ == Person + assert "supervisor" in Person.model_fields + assert Person.model_fields["supervisor"].annotation == Optional[Person] assert "supervisor" in Person.ormar_config.table.columns assert isinstance( diff --git a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py index 3f3754564..d18f8b1e0 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py +++ b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py @@ -17,8 +17,9 @@ database=database, ) + class SelfRef(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "self_refs") + ormar_config = base_ormar_config.copy(tablename="self_refs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="selfref") @@ -29,7 +30,7 @@ class SelfRef(ormar.Model): class Category(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "categories") + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -44,14 +45,14 @@ class Item(ormar.Model): class MutualA(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "mutual_a") + ormar_config = base_ormar_config.copy(tablename="mutual_a") id: int = ormar.Integer(primary_key=True) mutual_b = ormar.ForeignKey(ForwardRef("MutualB"), related_name="mutuals_a") class MutualB(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "mutual_b") + ormar_config = base_ormar_config.copy(tablename="mutual_b") id: int = ormar.Integer(primary_key=True) name = ormar.String(max_length=100, default="test") @@ -64,23 +65,28 @@ class MutualB(ormar.Model): def test_getting_pydantic_model(): PydanticCategory = Category.get_pydantic() assert issubclass(PydanticCategory, pydantic.BaseModel) - assert {*PydanticCategory.__fields__.keys()} == {"items", "id", "name"} + assert {*PydanticCategory.model_fields.keys()} == {"items", "id", "name"} - assert not PydanticCategory.__fields__["id"].required - assert PydanticCategory.__fields__["id"].outer_type_ == int - assert PydanticCategory.__fields__["id"].default is None + assert not PydanticCategory.model_fields["id"].is_required() + assert ( + PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["id"]["schema"]["schema"]["schema"]["type"] + == "int" + ) + assert PydanticCategory.model_fields["id"].default is None - assert PydanticCategory.__fields__["name"].required - assert issubclass(PydanticCategory.__fields__["name"].outer_type_, str) - assert PydanticCategory.__fields__["name"].default in [None, Ellipsis] + assert PydanticCategory.model_fields["name"].is_required() + assert PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["name"]["schema"]["type"] == "str" + assert PydanticCategory.model_fields["name"].default in [None, Ellipsis] - PydanticItem = PydanticCategory.__fields__["items"].type_ - assert PydanticCategory.__fields__["items"].outer_type_ == List[PydanticItem] + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"][ + "items_schema" + ]["cls"] + assert PydanticCategory.model_fields["items"].outer_type_ == List[PydanticItem] assert issubclass(PydanticItem, pydantic.BaseModel) - assert not PydanticItem.__fields__["name"].required - assert PydanticItem.__fields__["name"].default == "test" - assert issubclass(PydanticItem.__fields__["name"].outer_type_, str) - assert "category" not in PydanticItem.__fields__ + assert not PydanticItem.model_fields["name"].is_required() + assert PydanticItem.model_fields["name"].default == "test" + assert issubclass(PydanticItem.model_fields["name"].outer_type_, str) + assert "category" not in PydanticItem.model_fields def test_initializing_pydantic_model(): @@ -90,6 +96,8 @@ def test_initializing_pydantic_model(): "items": [{"id": 1, "name": "test_i1"}, {"id": 2, "name": "test_i2"}], } PydanticCategory = Category.get_pydantic() + ormar_cat = Category(**data) + assert ormar_cat.dict() == data cat = PydanticCategory(**data) assert cat.dict() == data @@ -100,130 +108,155 @@ def test_initializing_pydantic_model(): def test_getting_pydantic_model_include(): PydanticCategory = Category.get_pydantic(include={"id", "name"}) - assert len(PydanticCategory.__fields__) == 2 - assert "items" not in PydanticCategory.__fields__ + assert len(PydanticCategory.model_fields) == 2 + assert "items" not in PydanticCategory.model_fields def test_getting_pydantic_model_nested_include_set(): PydanticCategory = Category.get_pydantic(include={"id", "items__id"}) - assert len(PydanticCategory.__fields__) == 2 - assert "name" not in PydanticCategory.__fields__ - PydanticItem = PydanticCategory.__fields__["items"].type_ - assert len(PydanticItem.__fields__) == 1 - assert "id" in PydanticItem.__fields__ + assert len(PydanticCategory.model_fields) == 2 + assert "name" not in PydanticCategory.model_fields + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ + "items_schema" + ]["cls"] + assert len(PydanticItem.model_fields) == 1 + assert "id" in PydanticItem.model_fields def test_getting_pydantic_model_nested_include_dict(): PydanticCategory = Category.get_pydantic(include={"id": ..., "items": {"id"}}) - assert len(PydanticCategory.__fields__) == 2 - assert "name" not in PydanticCategory.__fields__ - PydanticItem = PydanticCategory.__fields__["items"].type_ - assert len(PydanticItem.__fields__) == 1 - assert "id" in PydanticItem.__fields__ + assert len(PydanticCategory.model_fields) == 2 + assert "name" not in PydanticCategory.model_fields + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ + "items_schema" + ]["cls"] + assert len(PydanticItem.model_fields) == 1 + assert "id" in PydanticItem.model_fields def test_getting_pydantic_model_nested_include_nested_dict(): PydanticCategory = Category.get_pydantic(include={"id": ..., "items": {"id": ...}}) - assert len(PydanticCategory.__fields__) == 2 - assert "name" not in PydanticCategory.__fields__ - PydanticItem = PydanticCategory.__fields__["items"].type_ - assert len(PydanticItem.__fields__) == 1 - assert "id" in PydanticItem.__fields__ + assert len(PydanticCategory.model_fields) == 2 + assert "name" not in PydanticCategory.model_fields + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ + "items_schema" + ]["cls"] + assert len(PydanticItem.model_fields) == 1 + assert "id" in PydanticItem.model_fields def test_getting_pydantic_model_include_exclude(): - PydanticCategory = Category.get_pydantic( - include={"id": ..., "items": {"id", "name"}}, exclude={"items__name"} - ) - assert len(PydanticCategory.__fields__) == 2 - assert "name" not in PydanticCategory.__fields__ - PydanticItem = PydanticCategory.__fields__["items"].type_ - assert len(PydanticItem.__fields__) == 1 - assert "id" in PydanticItem.__fields__ + PydanticCategory = Category.get_pydantic(include={"id": ..., "items": {"id", "name"}}, exclude={"items__name"}) + assert len(PydanticCategory.model_fields) == 2 + assert "name" not in PydanticCategory.model_fields + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ + "items_schema" + ]["cls"] + assert len(PydanticItem.model_fields) == 1 + assert "id" in PydanticItem.model_fields def test_getting_pydantic_model_exclude(): PydanticItem = Item.get_pydantic(exclude={"category__name"}) - assert len(PydanticItem.__fields__) == 3 - assert "category" in PydanticItem.__fields__ - PydanticCategory = PydanticItem.__fields__["category"].type_ - assert len(PydanticCategory.__fields__) == 1 - assert "name" not in PydanticCategory.__fields__ + assert len(PydanticItem.model_fields) == 3 + assert "category" in PydanticItem.model_fields + PydanticCategory = PydanticItem.__pydantic_core_schema__["schema"]["fields"]["category"]["schema"]["schema"][ + "schema" + ]["cls"] + assert len(PydanticCategory.model_fields) == 1 + assert "name" not in PydanticCategory.model_fields def test_getting_pydantic_model_exclude_dict(): PydanticItem = Item.get_pydantic(exclude={"id": ..., "category": {"name"}}) - assert len(PydanticItem.__fields__) == 2 - assert "category" in PydanticItem.__fields__ - assert "id" not in PydanticItem.__fields__ - PydanticCategory = PydanticItem.__fields__["category"].type_ - assert len(PydanticCategory.__fields__) == 1 - assert "name" not in PydanticCategory.__fields__ + assert len(PydanticItem.model_fields) == 2 + assert "category" in PydanticItem.model_fields + assert "id" not in PydanticItem.model_fields + PydanticCategory = PydanticItem.__pydantic_core_schema__["schema"]["fields"]["category"]["schema"]["schema"][ + "schema" + ]["cls"] + assert len(PydanticCategory.model_fields) == 1 + assert "name" not in PydanticCategory.model_fields def test_getting_pydantic_model_self_ref(): PydanticSelfRef = SelfRef.get_pydantic() - assert len(PydanticSelfRef.__fields__) == 4 - assert set(PydanticSelfRef.__fields__.keys()) == { + assert len(PydanticSelfRef.model_fields) == 4 + assert set(PydanticSelfRef.model_fields.keys()) == { "id", "name", "parent", "children", } - InnerSelf = PydanticSelfRef.__fields__["parent"].type_ - assert len(InnerSelf.__fields__) == 2 - assert set(InnerSelf.__fields__.keys()) == {"id", "name"} - - InnerSelf2 = PydanticSelfRef.__fields__["children"].type_ - assert len(InnerSelf2.__fields__) == 2 - assert set(InnerSelf2.__fields__.keys()) == {"id", "name"} + inner_self_ref_id = PydanticSelfRef.__pydantic_core_schema__["schema"]["schema"]["fields"]["parent"]["schema"][ + "schema" + ]["schema"]["schema_ref"] + InnerSelf = next( + (x for x in PydanticSelfRef.__pydantic_core_schema__["definitions"] if x["ref"] == inner_self_ref_id) + )["cls"] + assert len(InnerSelf.model_fields) == 2 + assert set(InnerSelf.model_fields.keys()) == {"id", "name"} + + inner_self_ref_id2 = PydanticSelfRef.__pydantic_core_schema__["schema"]["schema"]["fields"]["children"]["schema"][ + "schema" + ]["schema"]["items_schema"]["schema_ref"] + InnerSelf2 = next( + (x for x in PydanticSelfRef.__pydantic_core_schema__["definitions"] if x["ref"] == inner_self_ref_id2) + )["cls"] + assert len(InnerSelf2.model_fields) == 2 + assert set(InnerSelf2.model_fields.keys()) == {"id", "name"} def test_getting_pydantic_model_self_ref_exclude(): PydanticSelfRef = SelfRef.get_pydantic(exclude={"children": {"name"}}) - assert len(PydanticSelfRef.__fields__) == 4 - assert set(PydanticSelfRef.__fields__.keys()) == { + assert len(PydanticSelfRef.model_fields) == 4 + assert set(PydanticSelfRef.model_fields.keys()) == { "id", "name", "parent", "children", } - InnerSelf = PydanticSelfRef.__fields__["parent"].type_ - assert len(InnerSelf.__fields__) == 2 - assert set(InnerSelf.__fields__.keys()) == {"id", "name"} - - PydanticSelfRefChildren = PydanticSelfRef.__fields__["children"].type_ - assert len(PydanticSelfRefChildren.__fields__) == 1 - assert set(PydanticSelfRefChildren.__fields__.keys()) == {"id"} + InnerSelf = PydanticSelfRef.__pydantic_core_schema__["schema"]["fields"]["parent"]["schema"][ + "schema" + ]["schema"]["cls"] + assert len(InnerSelf.model_fields) == 2 + assert set(InnerSelf.model_fields.keys()) == {"id", "name"} + + # PydanticSelfRefChildren = PydanticSelfRef.model_fields["children"].type_ + PydanticSelfRefChildren = PydanticSelfRef.__pydantic_core_schema__["schema"]["fields"]["children"]["schema"][ + "schema" + ]["schema"]["items_schema"]["cls"] + assert len(PydanticSelfRefChildren.model_fields) == 1 + assert set(PydanticSelfRefChildren.model_fields.keys()) == {"id"} assert PydanticSelfRef != PydanticSelfRefChildren assert InnerSelf != PydanticSelfRefChildren def test_getting_pydantic_model_mutual_rels(): MutualAPydantic = MutualA.get_pydantic() - assert len(MutualAPydantic.__fields__) == 3 - assert set(MutualAPydantic.__fields__.keys()) == {"id", "mutual_b", "mutuals_b"} - - MutualB1 = MutualAPydantic.__fields__["mutual_b"].type_ - MutualB2 = MutualAPydantic.__fields__["mutuals_b"].type_ - assert len(MutualB1.__fields__) == 2 - assert set(MutualB1.__fields__.keys()) == {"id", "name"} - assert len(MutualB2.__fields__) == 2 - assert set(MutualB2.__fields__.keys()) == {"id", "name"} + assert len(MutualAPydantic.model_fields) == 3 + assert set(MutualAPydantic.model_fields.keys()) == {"id", "mutual_b", "mutuals_b"} + + MutualB1 = MutualAPydantic.model_fields["mutual_b"].type_ + MutualB2 = MutualAPydantic.model_fields["mutuals_b"].type_ + assert len(MutualB1.model_fields) == 2 + assert set(MutualB1.model_fields.keys()) == {"id", "name"} + assert len(MutualB2.model_fields) == 2 + assert set(MutualB2.model_fields.keys()) == {"id", "name"} assert MutualB1 == MutualB2 def test_getting_pydantic_model_mutual_rels_exclude(): MutualAPydantic = MutualA.get_pydantic(exclude={"mutual_b": {"name"}}) - assert len(MutualAPydantic.__fields__) == 3 - assert set(MutualAPydantic.__fields__.keys()) == {"id", "mutual_b", "mutuals_b"} + assert len(MutualAPydantic.model_fields) == 3 + assert set(MutualAPydantic.model_fields.keys()) == {"id", "mutual_b", "mutuals_b"} - MutualB1 = MutualAPydantic.__fields__["mutual_b"].type_ - MutualB2 = MutualAPydantic.__fields__["mutuals_b"].type_ + MutualB1 = MutualAPydantic.model_fields["mutual_b"].type_ + MutualB2 = MutualAPydantic.model_fields["mutuals_b"].type_ - assert len(MutualB1.__fields__) == 1 - assert set(MutualB1.__fields__.keys()) == {"id"} - assert len(MutualB2.__fields__) == 2 - assert set(MutualB2.__fields__.keys()) == {"id", "name"} + assert len(MutualB1.model_fields) == 1 + assert set(MutualB1.model_fields.keys()) == {"id"} + assert len(MutualB2.model_fields) == 2 + assert set(MutualB2.model_fields.keys()) == {"id", "name"} assert MutualB1 != MutualB2 From 14ffb792d161ffe1708a3add5b8670bcd5956ce1 Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 14 Dec 2023 18:10:33 +0100 Subject: [PATCH 06/95] WIP fix validation in update by creating individual fields validators, failing 36/443 --- ormar/models/helpers/models.py | 1 + ormar/models/mixins/save_mixin.py | 27 ++++++++++++++++++++++++++- ormar/models/newbasemodel.py | 2 ++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/ormar/models/helpers/models.py b/ormar/models/helpers/models.py index 3a1858d11..cdc0404a6 100644 --- a/ormar/models/helpers/models.py +++ b/ormar/models/helpers/models.py @@ -59,6 +59,7 @@ def populate_default_options_values( # noqa: CCR001 } new_model.__relation_map__ = None + new_model.__ormar_fields_validators__ = None class Connection(sqlite3.Connection): diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index 5c73cd34c..1608d9a97 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -14,6 +14,7 @@ ) import pydantic +from pydantic.plugin._schema_validator import create_schema_validator import ormar # noqa: I100, I202 from ormar.exceptions import ModelPersistenceError @@ -253,9 +254,33 @@ def validate_choices(cls, new_kwargs: Dict) -> Dict: :return: dictionary of model that is about to be saved :rtype: Dict """ - cls.__pydantic_validator__.validate_python(new_kwargs) # type: ignore + validators = cls._build_individual_schema_validator() + for key, value in new_kwargs.items(): + if key in validators: + validators[key].validate_python(value) return new_kwargs + @classmethod + def _build_individual_schema_validator(cls) -> Any: + if cls.__ormar_fields_validators__ is not None: + return cls.__ormar_fields_validators__ + field_validators = {} + for key, field in cls._extract_pydantic_fields().items(): + if cls.__pydantic_core_schema__["type"] == "definitions": + schema = {"type": "definitions", "schema": field["schema"], "definitions": cls.__pydantic_core_schema__["definitions"]} + else: + schema = field["schema"] + field_validators[key] = create_schema_validator(schema, cls, cls.__module__, cls.__qualname__,'BaseModel') + cls.__ormar_fields_validators__ = field_validators + return cls.__ormar_fields_validators__ + + @classmethod + def _extract_pydantic_fields(cls): + if cls.__pydantic_core_schema__["type"] == "model": + return cls.__pydantic_core_schema__["schema"]["fields"] + elif cls.__pydantic_core_schema__["type"] == "definitions": + return cls.__pydantic_core_schema__["schema"]["schema"]["fields"] + @staticmethod async def _upsert_model( instance: "Model", diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 2abfeaed7..0bde4520d 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -75,6 +75,8 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass "_pk_column", "__pk_only__", "__cached_hash__", + "__pydantic_extra__", + "__pydantic_fields_set__" ) if TYPE_CHECKING: # pragma no cover From 4fa7b31c2621a2211bb208ac80db8fa48146817f Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 14 Dec 2023 18:29:34 +0100 Subject: [PATCH 07/95] WIP fix __pydantic_extra__ in intializing model, fix test related to pydantic config checks, failing 32/442 --- ormar/models/metaclass.py | 2 +- ormar/models/newbasemodel.py | 6 +++--- .../test_inheritance_concrete.py | 11 ++--------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 7410d6844..01d742872 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -381,7 +381,7 @@ def copy_data_from_parent_model( # noqa: CCR001 meta = attrs.get("ormar_config") if not meta: # pragma: no cover raise ModelDefinitionError( - f"Model {curr_class.__name__} declared without Meta" + f"Model {curr_class.__name__} declared without ormar_config" ) table_name = ( meta.tablename diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 0bde4520d..ff196856b 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -1,10 +1,8 @@ import base64 import sys -import warnings from typing import ( AbstractSet, Any, - Callable, Dict, List, Mapping, @@ -23,7 +21,6 @@ import pydantic import sqlalchemy from pydantic import BaseModel -from pydantic_core import SchemaValidator import ormar # noqa I100 @@ -206,6 +203,9 @@ def __getattr__(self, item: str) -> Any: :rtype: Any """ # TODO: To many fields land here - descriptors problem? + # TODO: Check __pydantic_extra__ + if item == "__pydantic_extra__": + return None return super().__getattr__(item) def __getstate__(self) -> Dict[Any, Any]: diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index b76746be8..9790386aa 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -186,13 +186,6 @@ class Bus3(Car2): # pragma: no cover max_persons: int = ormar.Integer() -def test_config_is_not_a_class_raises_error(): - with pytest.raises(ModelDefinitionError): - - class ImmutablePerson2(Person): - Config = dict(allow_mutation=False, validate_assignment=False) - - def test_field_redefining_in_concrete_models(): class RedefinedField(DateFieldsModel): ormar_config = ormar.OrmarConfig( @@ -484,9 +477,9 @@ async def test_inheritance_with_multi_relation(): def test_custom_config(): # Custom config inherits defaults - assert getattr(ImmutablePerson.__config__, "orm_mode") is True + assert getattr(ImmutablePerson.model_config, "orm_mode") is True # Custom config can override defaults - assert getattr(ImmutablePerson.__config__, "validate_assignment") is False + assert getattr(ImmutablePerson.model_config, "validate_assignment") is False sam = ImmutablePerson(name="Sam") with pytest.raises(TypeError): sam.name = "Not Sam" From f7a7efb62eed756ca5a3a8dd33c4e107f7714c61 Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 14 Dec 2023 18:37:37 +0100 Subject: [PATCH 08/95] WIP - fix enum schema in model_json_schema, failing 31/442 --- tests/test_fastapi/test_enum_schema.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_fastapi/test_enum_schema.py b/tests/test_fastapi/test_enum_schema.py index 1fccf1ab3..a7d487851 100644 --- a/tests/test_fastapi/test_enum_schema.py +++ b/tests/test_fastapi/test_enum_schema.py @@ -27,5 +27,7 @@ class EnumExample(ormar.Model): def test_proper_schema(): - schema = EnumExample.schema_json() - assert '{"MyEnum": {"title": "MyEnum", "description": "An enumeration.", ' '"enum": [1, 2]}}' in schema + schema = EnumExample.model_json_schema() + assert {"MyEnum": {"title": "MyEnum", "enum": [1, 2], "type": "integer"}} == schema[ + "$defs" + ] From 6c2e92a4446b37ff9e21be3f2f8ff5edd71e3965 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 15 Dec 2023 19:31:21 +0100 Subject: [PATCH 09/95] WIP - fix copying through model, fix setting pydantic fields on through, fix default config and inheriting from it, failing 26/442 --- ormar/models/helpers/__init__.py | 2 - ormar/models/helpers/pydantic.py | 37 +- ormar/models/metaclass.py | 39 +- poetry.lock | 770 +++++++----------- pyproject.toml | 6 +- .../test_inheritance_concrete.py | 9 +- 6 files changed, 358 insertions(+), 505 deletions(-) diff --git a/ormar/models/helpers/__init__.py b/ormar/models/helpers/__init__.py index f9a725ca1..21d9f1ecb 100644 --- a/ormar/models/helpers/__init__.py +++ b/ormar/models/helpers/__init__.py @@ -7,7 +7,6 @@ from ormar.models.helpers.pydantic import ( get_potential_fields, get_pydantic_base_orm_config, - get_pydantic_field, merge_or_generate_pydantic_config, remove_excluded_parent_fields, ) @@ -31,7 +30,6 @@ "populate_default_options_values", "alias_manager", "register_relation_in_alias_manager", - "get_pydantic_field", "get_potential_fields", "get_pydantic_base_orm_config", "merge_or_generate_pydantic_config", diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index 351af9926..f5dc6c647 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -4,7 +4,7 @@ import pydantic from pydantic import ConfigDict -from pydantic.fields import Field +from pydantic.fields import Field, FieldInfo from pydantic.utils import lenient_issubclass from pydantic_core import PydanticUndefined @@ -32,37 +32,8 @@ def create_pydantic_field( :param model_field: relation field from which through model is extracted :type model_field: ManyToManyField class """ - model_field.through.__fields__[field_name] = Field( - name=field_name, - type_=model, - model_config=model.model_config, - required=False, - class_validators={}, - ) - - -def get_pydantic_field(field_name: str, model: Type["Model"]) -> "Field": - """ - Extracts field type and if it's required from Model model_fields by passed - field_name. Returns a pydantic field with type of field_name field type. - - :param field_name: field name to fetch from Model and name of pydantic field - :type field_name: str - :param model: type of field to register - :type model: Model class - :return: newly created pydantic field - :rtype: pydantic.Field - """ - type_ = model.ormar_config.model_fields[field_name].__type__ - return Field( - name=field_name, - type_=type_, # type: ignore - model_config=model.model_config, - default=None - if model.ormar_config.model_fields[field_name].nullable - else PydanticUndefined, - class_validators={}, - ) + model_field.through.model_fields[field_name] = FieldInfo.from_annotated_attribute(annotation=model, default=None) + model_field.through.model_rebuild(force=True) def populate_pydantic_default_values(attrs: Dict) -> Tuple[Dict, Dict]: @@ -119,7 +90,7 @@ def merge_or_generate_pydantic_config(attrs: Dict, name: str) -> None: f"Config provided for class {name} has to be a dictionary." ) - config = default_config.update(provided_config) + config = {**default_config, **provided_config} attrs["model_config"] = config else: attrs["model_config"] = default_config diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 01d742872..27709acf7 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -1,3 +1,4 @@ +import copy from typing import ( Any, Dict, @@ -42,7 +43,6 @@ expand_reverse_relationships, extract_annotations_and_default_vals, get_potential_fields, - get_pydantic_field, merge_or_generate_pydantic_config, config_field_not_set, populate_default_options_values, @@ -312,15 +312,33 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 field.create_default_through_model() through_class = field.through # TODO: CHECK PKNAME - new_meta = ormar.OrmarConfig() - new_meta.__dict__ = through_class.ormar_config.__dict__.copy() + new_meta = ormar.OrmarConfig( + tablename=through_class.ormar_config.tablename, + metadata=through_class.ormar_config.metadata, + database=through_class.ormar_config.database, + abstract=through_class.ormar_config.abstract, + exclude_parent_fields=through_class.ormar_config.exclude_parent_fields, + queryset_class=through_class.ormar_config.queryset_class, + extra=through_class.ormar_config.extra, + constraints=through_class.ormar_config.constraints, + order_by=through_class.ormar_config.orders_by, + + ) + new_meta.columns = None + new_meta.table = through_class.ormar_config.pkname + new_meta.pkname = through_class.ormar_config.pkname + new_meta.alias_manager = through_class.ormar_config.alias_manager + new_meta.signals = through_class.ormar_config.signals + new_meta.requires_ref_update = through_class.ormar_config.requires_ref_update + new_meta.model_fields = copy.deepcopy(through_class.ormar_config.model_fields) + new_meta.property_fields = copy.deepcopy(through_class.ormar_config.property_fields) copy_name = through_class.__name__ + attrs.get("__name__", "") copy_through = type(copy_name, (ormar.Model,), {"ormar_config": new_meta}) - new_meta.tablename += "_" + meta.tablename # create new table with copied columns but remove foreign keys # they will be populated later in expanding reverse relation - if hasattr(new_meta, "table"): - new_meta.table = None + # if hasattr(new_meta, "table"): + new_meta.tablename += "_" + meta.tablename + new_meta.table = None new_meta.model_fields = { name: field for name, field in new_meta.model_fields.items() @@ -600,12 +618,14 @@ def __new__( # type: ignore # noqa: CCR001 ) if "ormar_config" in attrs: attrs["model_config"]["ignored_types"] = (OrmarConfig,) + attrs["model_config"]["from_attributes"] = True new_model = super().__new__(mcs, name, bases, attrs) # type: ignore add_cached_properties(new_model) if hasattr(new_model, "ormar_config"): - populate_default_options_values(new_model, model_fields) + if model_fields: + populate_default_options_values(new_model, model_fields) check_required_meta_parameters(new_model) add_property_fields(new_model, attrs) register_signals(new_model=new_model) @@ -628,10 +648,9 @@ def __new__( # type: ignore # noqa: CCR001 and new_model.ormar_config.pkname not in new_model.model_fields ): field_name = new_model.ormar_config.pkname - new_model.model_fields[field_name] = FieldInfo.from_annotation( - Optional[int] + new_model.model_fields[field_name] = FieldInfo.from_annotated_attribute( + Optional[int], None ) - new_model.model_fields[field_name].default = None new_model.model_rebuild(force=True) for item in new_model.ormar_config.property_fields: diff --git a/poetry.lock b/poetry.lock index 901c40e97..726a15951 100644 --- a/poetry.lock +++ b/poetry.lock @@ -50,23 +50,20 @@ files = [ {file = "aiosqlite-0.19.0.tar.gz", hash = "sha256:95ee77b91c8d2808bd08a59fbebf66270e9090c3d92ffbf260dc0db0b979577d"}, ] -[package.dependencies] -typing_extensions = {version = ">=4.0", markers = "python_version < \"3.8\""} - [package.extras] dev = ["aiounittest (==1.4.1)", "attribution (==1.6.2)", "black (==23.3.0)", "coverage[toml] (==7.2.3)", "flake8 (==5.0.4)", "flake8-bugbear (==23.3.12)", "flit (==3.7.1)", "mypy (==1.2.0)", "ufmt (==2.1.0)", "usort (==1.0.6)"] docs = ["sphinx (==6.1.3)", "sphinx-mdinclude (==0.5.3)"] [[package]] name = "annotated-types" -version = "0.5.0" +version = "0.6.0" description = "Reusable constraint types to use with typing.Annotated" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, - {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, ] [package.dependencies] @@ -88,7 +85,6 @@ files = [ exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] @@ -112,19 +108,16 @@ sniffio = "*" [[package]] name = "astpretty" -version = "2.1.0" +version = "3.0.0" description = "Pretty print the output of python stdlib `ast.parse`." category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.8" files = [ - {file = "astpretty-2.1.0-py2.py3-none-any.whl", hash = "sha256:f81f14b5636f7af81fadb1e3c09ca7702ce4615500d9cc6d6829befb2dec2e3c"}, - {file = "astpretty-2.1.0.tar.gz", hash = "sha256:8a801fcda604ec741f010bb36d7cbadc3ec8a182ea6fb83e20ab663463e75ff6"}, + {file = "astpretty-3.0.0-py2.py3-none-any.whl", hash = "sha256:15bfd47593667169485a1fa7938b8de9445b11057d6f2b6e214b2f70667f94b6"}, + {file = "astpretty-3.0.0.tar.gz", hash = "sha256:b08c95f32e5994454ea99882ff3c4a0afc8254c38998a0ed4b479dba448dc581"}, ] -[package.extras] -typed = ["typed-ast"] - [[package]] name = "async-timeout" version = "4.0.3" @@ -137,9 +130,6 @@ files = [ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, ] -[package.dependencies] -typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} - [[package]] name = "asyncpg" version = "0.27.0" @@ -186,9 +176,6 @@ files = [ {file = "asyncpg-0.27.0.tar.gz", hash = "sha256:720986d9a4705dd8a40fdf172036f5ae787225036a7eb46e704c45aa8f62c054"}, ] -[package.dependencies] -typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} - [package.extras] dev = ["Cython (>=0.29.24,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "flake8 (>=5.0.4,<5.1.0)", "pytest (>=6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "uvloop (>=0.15.3)"] docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] @@ -206,9 +193,6 @@ files = [ {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, ] -[package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] dev = ["attrs[docs,tests]", "pre-commit"] @@ -218,19 +202,19 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte [[package]] name = "bandit" -version = "1.7.5" +version = "1.7.6" description = "Security oriented static analyser for python code." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "bandit-1.7.5-py3-none-any.whl", hash = "sha256:75665181dc1e0096369112541a056c59d1c5f66f9bb74a8d686c3c362b83f549"}, - {file = "bandit-1.7.5.tar.gz", hash = "sha256:bdfc739baa03b880c2d15d0431b31c658ffc348e907fe197e54e0389dd59e11e"}, + {file = "bandit-1.7.6-py3-none-any.whl", hash = "sha256:36da17c67fc87579a5d20c323c8d0b1643a890a2b93f00b3d1229966624694ff"}, + {file = "bandit-1.7.6.tar.gz", hash = "sha256:72ce7bc9741374d96fb2f1c9a8960829885f1243ffde743de70a19cee353e8f3"}, ] [package.dependencies] colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} -GitPython = ">=1.0.1" +GitPython = ">=3.1.30" PyYAML = ">=5.3.1" rich = "*" stevedore = ">=1.20.0" @@ -242,37 +226,34 @@ yaml = ["PyYAML"] [[package]] name = "black" -version = "23.3.0" +version = "23.12.0" description = "The uncompromising code formatter." category = "dev" optional = false -python-versions = ">=3.7" -files = [ - {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, - {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, - {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, - {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, - {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, - {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, - {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, - {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, - {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, - {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, - {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, - {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, - {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, - {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, +python-versions = ">=3.8" +files = [ + {file = "black-23.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67f19562d367468ab59bd6c36a72b2c84bc2f16b59788690e02bbcb140a77175"}, + {file = "black-23.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbd75d9f28a7283b7426160ca21c5bd640ca7cd8ef6630b4754b6df9e2da8462"}, + {file = "black-23.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:593596f699ca2dcbbbdfa59fcda7d8ad6604370c10228223cd6cf6ce1ce7ed7e"}, + {file = "black-23.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:12d5f10cce8dc27202e9a252acd1c9a426c83f95496c959406c96b785a92bb7d"}, + {file = "black-23.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e73c5e3d37e5a3513d16b33305713237a234396ae56769b839d7c40759b8a41c"}, + {file = "black-23.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba09cae1657c4f8a8c9ff6cfd4a6baaf915bb4ef7d03acffe6a2f6585fa1bd01"}, + {file = "black-23.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace64c1a349c162d6da3cef91e3b0e78c4fc596ffde9413efa0525456148873d"}, + {file = "black-23.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:72db37a2266b16d256b3ea88b9affcdd5c41a74db551ec3dd4609a59c17d25bf"}, + {file = "black-23.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fdf6f23c83078a6c8da2442f4d4eeb19c28ac2a6416da7671b72f0295c4a697b"}, + {file = "black-23.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39dda060b9b395a6b7bf9c5db28ac87b3c3f48d4fdff470fa8a94ab8271da47e"}, + {file = "black-23.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7231670266ca5191a76cb838185d9be59cfa4f5dd401b7c1c70b993c58f6b1b5"}, + {file = "black-23.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:193946e634e80bfb3aec41830f5d7431f8dd5b20d11d89be14b84a97c6b8bc75"}, + {file = "black-23.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcf91b01ddd91a2fed9a8006d7baa94ccefe7e518556470cf40213bd3d44bbbc"}, + {file = "black-23.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:996650a89fe5892714ea4ea87bc45e41a59a1e01675c42c433a35b490e5aa3f0"}, + {file = "black-23.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdbff34c487239a63d86db0c9385b27cdd68b1bfa4e706aa74bb94a435403672"}, + {file = "black-23.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:97af22278043a6a1272daca10a6f4d36c04dfa77e61cbaaf4482e08f3640e9f0"}, + {file = "black-23.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ead25c273adfad1095a8ad32afdb8304933efba56e3c1d31b0fee4143a1e424a"}, + {file = "black-23.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c71048345bdbced456cddf1622832276d98a710196b842407840ae8055ade6ee"}, + {file = "black-23.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a832b6e00eef2c13b3239d514ea3b7d5cc3eaa03d0474eedcbbda59441ba5d"}, + {file = "black-23.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:6a82a711d13e61840fb11a6dfecc7287f2424f1ca34765e70c909a35ffa7fb95"}, + {file = "black-23.12.0-py3-none-any.whl", hash = "sha256:a7c07db8200b5315dc07e331dda4d889a56f6bf4db6a9c2a526fa3166a81614f"}, + {file = "black-23.12.0.tar.gz", hash = "sha256:330a327b422aca0634ecd115985c1c7fd7bdb5b5a2ef8aa9888a82e2ebe9437a"}, ] [package.dependencies] @@ -282,27 +263,14 @@ packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] -[[package]] -name = "cached-property" -version = "1.5.2" -description = "A decorator for caching properties in classes." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, - {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, -] - [[package]] name = "certifi" version = "2023.11.17" @@ -317,76 +285,64 @@ files = [ [[package]] name = "cffi" -version = "1.15.1" +version = "1.16.0" description = "Foreign Function Interface for Python calling C code." category = "main" optional = true -python-versions = "*" -files = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] [package.dependencies] @@ -394,14 +350,14 @@ pycparser = "*" [[package]] name = "cfgv" -version = "3.3.1" +version = "3.4.0" description = "Validate configuration and produce human readable error messages." category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.8" files = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] [[package]] @@ -518,7 +474,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "codecov" @@ -564,72 +519,64 @@ files = [ [[package]] name = "coverage" -version = "7.2.7" +version = "7.3.3" description = "Code coverage measurement for Python" category = "dev" optional = false -python-versions = ">=3.7" -files = [ - {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, - {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, - {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, - {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, - {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, - {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, - {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, - {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, - {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, - {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, - {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, - {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, - {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, - {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, - {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, - {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, - {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, - {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, +python-versions = ">=3.8" +files = [ + {file = "coverage-7.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d874434e0cb7b90f7af2b6e3309b0733cde8ec1476eb47db148ed7deeb2a9494"}, + {file = "coverage-7.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee6621dccce8af666b8c4651f9f43467bfbf409607c604b840b78f4ff3619aeb"}, + {file = "coverage-7.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1367aa411afb4431ab58fd7ee102adb2665894d047c490649e86219327183134"}, + {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f0f8f0c497eb9c9f18f21de0750c8d8b4b9c7000b43996a094290b59d0e7523"}, + {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db0338c4b0951d93d547e0ff8d8ea340fecf5885f5b00b23be5aa99549e14cfd"}, + {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d31650d313bd90d027f4be7663dfa2241079edd780b56ac416b56eebe0a21aab"}, + {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9437a4074b43c177c92c96d051957592afd85ba00d3e92002c8ef45ee75df438"}, + {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9e17d9cb06c13b4f2ef570355fa45797d10f19ca71395910b249e3f77942a837"}, + {file = "coverage-7.3.3-cp310-cp310-win32.whl", hash = "sha256:eee5e741b43ea1b49d98ab6e40f7e299e97715af2488d1c77a90de4a663a86e2"}, + {file = "coverage-7.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:593efa42160c15c59ee9b66c5f27a453ed3968718e6e58431cdfb2d50d5ad284"}, + {file = "coverage-7.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c944cf1775235c0857829c275c777a2c3e33032e544bcef614036f337ac37bb"}, + {file = "coverage-7.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eda7f6e92358ac9e1717ce1f0377ed2b9320cea070906ece4e5c11d172a45a39"}, + {file = "coverage-7.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c854c1d2c7d3e47f7120b560d1a30c1ca221e207439608d27bc4d08fd4aeae8"}, + {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:222b038f08a7ebed1e4e78ccf3c09a1ca4ac3da16de983e66520973443b546bc"}, + {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff4800783d85bff132f2cc7d007426ec698cdce08c3062c8d501ad3f4ea3d16c"}, + {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fc200cec654311ca2c3f5ab3ce2220521b3d4732f68e1b1e79bef8fcfc1f2b97"}, + {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:307aecb65bb77cbfebf2eb6e12009e9034d050c6c69d8a5f3f737b329f4f15fb"}, + {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ffb0eacbadb705c0a6969b0adf468f126b064f3362411df95f6d4f31c40d31c1"}, + {file = "coverage-7.3.3-cp311-cp311-win32.whl", hash = "sha256:79c32f875fd7c0ed8d642b221cf81feba98183d2ff14d1f37a1bbce6b0347d9f"}, + {file = "coverage-7.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:243576944f7c1a1205e5cd658533a50eba662c74f9be4c050d51c69bd4532936"}, + {file = "coverage-7.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a2ac4245f18057dfec3b0074c4eb366953bca6787f1ec397c004c78176a23d56"}, + {file = "coverage-7.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f9191be7af41f0b54324ded600e8ddbcabea23e1e8ba419d9a53b241dece821d"}, + {file = "coverage-7.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c0b1b8b5a4aebf8fcd227237fc4263aa7fa0ddcd4d288d42f50eff18b0bac4"}, + {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee453085279df1bac0996bc97004771a4a052b1f1e23f6101213e3796ff3cb85"}, + {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1191270b06ecd68b1d00897b2daddb98e1719f63750969614ceb3438228c088e"}, + {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:007a7e49831cfe387473e92e9ff07377f6121120669ddc39674e7244350a6a29"}, + {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:af75cf83c2d57717a8493ed2246d34b1f3398cb8a92b10fd7a1858cad8e78f59"}, + {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:811ca7373da32f1ccee2927dc27dc523462fd30674a80102f86c6753d6681bc6"}, + {file = "coverage-7.3.3-cp312-cp312-win32.whl", hash = "sha256:733537a182b5d62184f2a72796eb6901299898231a8e4f84c858c68684b25a70"}, + {file = "coverage-7.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:e995efb191f04b01ced307dbd7407ebf6e6dc209b528d75583277b10fd1800ee"}, + {file = "coverage-7.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbd8a5fe6c893de21a3c6835071ec116d79334fbdf641743332e442a3466f7ea"}, + {file = "coverage-7.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:50c472c1916540f8b2deef10cdc736cd2b3d1464d3945e4da0333862270dcb15"}, + {file = "coverage-7.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e9223a18f51d00d3ce239c39fc41410489ec7a248a84fab443fbb39c943616c"}, + {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f501e36ac428c1b334c41e196ff6bd550c0353c7314716e80055b1f0a32ba394"}, + {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:475de8213ed95a6b6283056d180b2442eee38d5948d735cd3d3b52b86dd65b92"}, + {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:afdcc10c01d0db217fc0a64f58c7edd635b8f27787fea0a3054b856a6dff8717"}, + {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fff0b2f249ac642fd735f009b8363c2b46cf406d3caec00e4deeb79b5ff39b40"}, + {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a1f76cfc122c9e0f62dbe0460ec9cc7696fc9a0293931a33b8870f78cf83a327"}, + {file = "coverage-7.3.3-cp38-cp38-win32.whl", hash = "sha256:757453848c18d7ab5d5b5f1827293d580f156f1c2c8cef45bfc21f37d8681069"}, + {file = "coverage-7.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad2453b852a1316c8a103c9c970db8fbc262f4f6b930aa6c606df9b2766eee06"}, + {file = "coverage-7.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b15e03b8ee6a908db48eccf4e4e42397f146ab1e91c6324da44197a45cb9132"}, + {file = "coverage-7.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:89400aa1752e09f666cc48708eaa171eef0ebe3d5f74044b614729231763ae69"}, + {file = "coverage-7.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c59a3e59fb95e6d72e71dc915e6d7fa568863fad0a80b33bc7b82d6e9f844973"}, + {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ede881c7618f9cf93e2df0421ee127afdfd267d1b5d0c59bcea771cf160ea4a"}, + {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3bfd2c2f0e5384276e12b14882bf2c7621f97c35320c3e7132c156ce18436a1"}, + {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7f3bad1a9313401ff2964e411ab7d57fb700a2d5478b727e13f156c8f89774a0"}, + {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:65d716b736f16e250435473c5ca01285d73c29f20097decdbb12571d5dfb2c94"}, + {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a702e66483b1fe602717020a0e90506e759c84a71dbc1616dd55d29d86a9b91f"}, + {file = "coverage-7.3.3-cp39-cp39-win32.whl", hash = "sha256:7fbf3f5756e7955174a31fb579307d69ffca91ad163467ed123858ce0f3fd4aa"}, + {file = "coverage-7.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cad9afc1644b979211989ec3ff7d82110b2ed52995c2f7263e7841c846a75348"}, + {file = "coverage-7.3.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:d299d379b676812e142fb57662a8d0d810b859421412b4d7af996154c00c31bb"}, + {file = "coverage-7.3.3.tar.gz", hash = "sha256:df04c64e58df96b4427db8d0559e95e2df3138c9916c96f9f6a4dd220db2fdb7"}, ] [package.dependencies] @@ -750,40 +697,41 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.103.2" +version = "0.105.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "fastapi-0.103.2-py3-none-any.whl", hash = "sha256:3270de872f0fe9ec809d4bd3d4d890c6d5cc7b9611d721d6438f9dacc8c4ef2e"}, - {file = "fastapi-0.103.2.tar.gz", hash = "sha256:75a11f6bfb8fc4d2bec0bd710c2d5f2829659c0e8c0afd5560fdda6ce25ec653"}, + {file = "fastapi-0.105.0-py3-none-any.whl", hash = "sha256:f19ebf6fdc82a3281d10f2cb4774bdfa90238e3b40af3525a0c09fd08ad1c480"}, + {file = "fastapi-0.105.0.tar.gz", hash = "sha256:4d12838819aa52af244580675825e750ad67c9df4614f557a769606af902cf22"}, ] [package.dependencies] anyio = ">=3.7.1,<4.0.0" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" starlette = ">=0.27.0,<0.28.0" -typing-extensions = ">=4.5.0" +typing-extensions = ">=4.8.0" [package.extras] all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" -version = "3.12.2" +version = "3.13.1" description = "A platform independent file lock." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "flake8" @@ -798,7 +746,6 @@ files = [ ] [package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.7.0,<2.8.0" pyflakes = ">=2.3.0,<2.4.0" @@ -862,14 +809,14 @@ dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", [[package]] name = "flake8-builtins" -version = "2.1.0" -description = "Check for python builtins being used as variables or parameters." +version = "2.2.0" +description = "Check for python builtins being used as variables or parameters" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "flake8-builtins-2.1.0.tar.gz", hash = "sha256:12ff1ee96dd4e1f3141141ee6c45a5c7d3b3c440d0949e9b8d345c42b39c51d4"}, - {file = "flake8_builtins-2.1.0-py3-none-any.whl", hash = "sha256:469e8f03d6d0edf4b1e62b6d5a97dce4598592c8a13ec8f0952e7a185eba50a1"}, + {file = "flake8_builtins-2.2.0-py3-none-any.whl", hash = "sha256:7ee5766d9c60e5d579dfda84e65c6d0e6c26005f6f59cb9bf722462d7987a807"}, + {file = "flake8_builtins-2.2.0.tar.gz", hash = "sha256:392d5af3a0720c5a863aa93dc47f48c879081345a143fe9f20d995fe9ff5686a"}, ] [package.dependencies] @@ -1015,7 +962,6 @@ files = [ [package.dependencies] gitdb = ">=4.0.1,<5" -typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} [package.extras] test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-sugar"] @@ -1094,18 +1040,17 @@ test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.30.1" +version = "0.38.1" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "griffe-0.30.1-py3-none-any.whl", hash = "sha256:b2f3df6952995a6bebe19f797189d67aba7c860755d3d21cc80f64d076d0154c"}, - {file = "griffe-0.30.1.tar.gz", hash = "sha256:007cc11acd20becf1bb8f826419a52b9d403bbad9d8c8535699f5440ddc0a109"}, + {file = "griffe-0.38.1-py3-none-any.whl", hash = "sha256:334c79d3b5964ade65c05dfcaf53518c576dedd387aaba5c9fd71212f34f1483"}, + {file = "griffe-0.38.1.tar.gz", hash = "sha256:bd68d7da7f3d87bc57eb9962b250db123efd9bbcc06c11c1a91b6e583b2a9361"}, ] [package.dependencies] -cached-property = {version = "*", markers = "python_version < \"3.8\""} colorama = ">=0.4" [[package]] @@ -1120,9 +1065,6 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] -[package.dependencies] -typing-extensions = {version = "*", markers = "python_version < \"3.8\""} - [[package]] name = "httpcore" version = "0.17.3" @@ -1171,14 +1113,14 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "identify" -version = "2.5.24" +version = "2.5.33" description = "File identification library for Python" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, - {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, + {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, + {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, ] [package.extras] @@ -1198,24 +1140,23 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.7.0" +version = "7.0.0" description = "Read metadata from Python packages" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, - {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, + {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, + {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, ] [package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] [[package]] name = "iniconfig" @@ -1249,38 +1190,37 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "markdown" -version = "3.4.4" +version = "3.5.1" description = "Python implementation of John Gruber's Markdown." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"}, - {file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"}, + {file = "Markdown-3.5.1-py3-none-any.whl", hash = "sha256:5874b47d4ee3f0b14d764324d2c94c03ea66bee56f2d929da9f2508d65e722dc"}, + {file = "Markdown-3.5.1.tar.gz", hash = "sha256:b65d7beb248dc22f2e8a31fb706d93798093c308dc1aba295aedeb9d41a813bd"}, ] [package.dependencies] importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} [package.extras] -docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] [[package]] name = "markdown-it-py" -version = "2.2.0" +version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"}, - {file = "markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"}, + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, ] [package.dependencies] mdurl = ">=0.1,<1.0" -typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [package.extras] benchmarking = ["psutil", "pytest", "pytest-benchmark"] @@ -1289,7 +1229,7 @@ compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0 linkify = ["linkify-it-py (>=1,<3)"] plugins = ["mdit-py-plugins"] profiling = ["gprof2dot"] -rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] @@ -1414,7 +1354,6 @@ pathspec = ">=0.11.1" platformdirs = ">=2.2.0" pyyaml = ">=5.1" pyyaml-env-tag = ">=0.1" -typing-extensions = {version = ">=3.10", markers = "python_version < \"3.8\""} watchdog = ">=2.0" [package.extras] @@ -1423,14 +1362,14 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp [[package]] name = "mkdocs-autorefs" -version = "0.4.1" +version = "0.5.0" description = "Automatically link across pages in MkDocs." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "mkdocs-autorefs-0.4.1.tar.gz", hash = "sha256:70748a7bd025f9ecd6d6feeba8ba63f8e891a1af55f48e366d6d6e78493aba84"}, - {file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"}, + {file = "mkdocs_autorefs-0.5.0-py3-none-any.whl", hash = "sha256:7930fcb8ac1249f10e683967aeaddc0af49d90702af111a5e390e8b20b3d97ff"}, + {file = "mkdocs_autorefs-0.5.0.tar.gz", hash = "sha256:9a5054a94c08d28855cfab967ada10ed5be76e2bfad642302a610b252c3274c0"}, ] [package.dependencies] @@ -1492,14 +1431,14 @@ requests = ">=2.26" [[package]] name = "mkdocs-material-extensions" -version = "1.2" +version = "1.3.1" description = "Extension pack for Python Markdown and MkDocs Material." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "mkdocs_material_extensions-1.2-py3-none-any.whl", hash = "sha256:c767bd6d6305f6420a50f0b541b0c9966d52068839af97029be14443849fb8a1"}, - {file = "mkdocs_material_extensions-1.2.tar.gz", hash = "sha256:27e2d1ed2d031426a6e10d5ea06989d67e90bb02acd588bc5673106b5ee5eedf"}, + {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, + {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, ] [[package]] @@ -1547,18 +1486,18 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] [[package]] name = "mkdocstrings-python" -version = "1.1.2" +version = "1.7.5" description = "A Python handler for mkdocstrings." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "mkdocstrings_python-1.1.2-py3-none-any.whl", hash = "sha256:c2b652a850fec8e85034a9cdb3b45f8ad1a558686edc20ed1f40b4e17e62070f"}, - {file = "mkdocstrings_python-1.1.2.tar.gz", hash = "sha256:f28bdcacb9bcdb44b6942a5642c1ea8b36870614d33e29e3c923e204a8d8ed61"}, + {file = "mkdocstrings_python-1.7.5-py3-none-any.whl", hash = "sha256:5f6246026353f0c0785135db70c3fe9a5d9318990fc7ceb11d62097b8ffdd704"}, + {file = "mkdocstrings_python-1.7.5.tar.gz", hash = "sha256:c7d143728257dbf1aa550446555a554b760dcd40a763f077189d298502b800be"}, ] [package.dependencies] -griffe = ">=0.24" +griffe = ">=0.37" mkdocstrings = ">=0.20" [[package]] @@ -1577,7 +1516,6 @@ files = [ click = ">=7.1.2" setuptools = "*" stdlib-list = ">=0.5.0" -typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} [[package]] name = "mypy" @@ -1616,7 +1554,6 @@ files = [ [package.dependencies] mypy-extensions = ">=0.4.3" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} typing-extensions = ">=3.10" [package.extras] @@ -1638,19 +1575,21 @@ files = [ [[package]] name = "mysqlclient" -version = "2.1.1" +version = "2.2.1" description = "Python interface to MySQL" category = "main" optional = true -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "mysqlclient-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c1ed71bd6244993b526113cca3df66428609f90e4652f37eb51c33496d478b37"}, - {file = "mysqlclient-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:c812b67e90082a840efb82a8978369e6e69fc62ce1bda4ca8f3084a9d862308b"}, - {file = "mysqlclient-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:0d1cd3a5a4d28c222fa199002810e8146cffd821410b67851af4cc80aeccd97c"}, - {file = "mysqlclient-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b355c8b5a7d58f2e909acdbb050858390ee1b0e13672ae759e5e784110022994"}, - {file = "mysqlclient-2.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:996924f3483fd36a34a5812210c69e71dea5a3d5978d01199b78b7f6d485c855"}, - {file = "mysqlclient-2.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:dea88c8d3f5a5d9293dfe7f087c16dd350ceb175f2f6631c9cf4caf3e19b7a96"}, - {file = "mysqlclient-2.1.1.tar.gz", hash = "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"}, + {file = "mysqlclient-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:c5a293baebbfcfa2905545198a54e90f1cf00f211eae6637d24930abb6432cba"}, + {file = "mysqlclient-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:8f40c872f19639366e3df27bef2ff087be0e3ee0bd3453470bd29f46b54a90f6"}, + {file = "mysqlclient-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:45600f4f321096bd1ead3355bc62cfcf8d97dc78df94e4ab5db72ecb5db1bd04"}, + {file = "mysqlclient-2.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f8889cc5f0141bb307b915e981a66793df663ace92259344661084a7dd8d12a"}, + {file = "mysqlclient-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:9db6305cdf2a1da350f827d2a19be7f2666eafd9eb8d4f7cbbac5df847d61b99"}, + {file = "mysqlclient-2.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:97eee76818774bb695e018ff4c3dafaab74b9a0b0cf32c90b02caeec3b19cd8e"}, + {file = "mysqlclient-2.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4fabe1f4b545ed6244ad0ff426e6b27054b7e5c5b1392be0de2e5f2f59be0392"}, + {file = "mysqlclient-2.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:641a7c9de443ddef186a0e89f24b4251ad44f4ddc5e7094332bf2d286d7c9e33"}, + {file = "mysqlclient-2.2.1.tar.gz", hash = "sha256:2c7ad15b87293b12fd44b47c46879ec95ec647f4567e866ccd70b8337584e9b2"}, ] [[package]] @@ -1682,72 +1621,62 @@ setuptools = "*" [[package]] name = "orjson" -version = "3.9.7" +version = "3.9.10" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = true -python-versions = ">=3.7" -files = [ - {file = "orjson-3.9.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6df858e37c321cefbf27fe7ece30a950bcc3a75618a804a0dcef7ed9dd9c92d"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5198633137780d78b86bb54dafaaa9baea698b4f059456cd4554ab7009619221"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e736815b30f7e3c9044ec06a98ee59e217a833227e10eb157f44071faddd7c5"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a19e4074bc98793458b4b3ba35a9a1d132179345e60e152a1bb48c538ab863c4"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80acafe396ab689a326ab0d80f8cc61dec0dd2c5dca5b4b3825e7b1e0132c101"}, - {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:355efdbbf0cecc3bd9b12589b8f8e9f03c813a115efa53f8dc2a523bfdb01334"}, - {file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3aab72d2cef7f1dd6104c89b0b4d6b416b0db5ca87cc2fac5f79c5601f549cc2"}, - {file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36b1df2e4095368ee388190687cb1b8557c67bc38400a942a1a77713580b50ae"}, - {file = "orjson-3.9.7-cp310-none-win32.whl", hash = "sha256:e94b7b31aa0d65f5b7c72dd8f8227dbd3e30354b99e7a9af096d967a77f2a580"}, - {file = "orjson-3.9.7-cp310-none-win_amd64.whl", hash = "sha256:82720ab0cf5bb436bbd97a319ac529aee06077ff7e61cab57cee04a596c4f9b4"}, - {file = "orjson-3.9.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1f8b47650f90e298b78ecf4df003f66f54acdba6a0f763cc4df1eab048fe3738"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f738fee63eb263530efd4d2e9c76316c1f47b3bbf38c1bf45ae9625feed0395e"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38e34c3a21ed41a7dbd5349e24c3725be5416641fdeedf8f56fcbab6d981c900"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21a3344163be3b2c7e22cef14fa5abe957a892b2ea0525ee86ad8186921b6cf0"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23be6b22aab83f440b62a6f5975bcabeecb672bc627face6a83bc7aeb495dc7e"}, - {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5205ec0dfab1887dd383597012199f5175035e782cdb013c542187d280ca443"}, - {file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8769806ea0b45d7bf75cad253fba9ac6700b7050ebb19337ff6b4e9060f963fa"}, - {file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f9e01239abea2f52a429fe9d95c96df95f078f0172489d691b4a848ace54a476"}, - {file = "orjson-3.9.7-cp311-none-win32.whl", hash = "sha256:8bdb6c911dae5fbf110fe4f5cba578437526334df381b3554b6ab7f626e5eeca"}, - {file = "orjson-3.9.7-cp311-none-win_amd64.whl", hash = "sha256:9d62c583b5110e6a5cf5169ab616aa4ec71f2c0c30f833306f9e378cf51b6c86"}, - {file = "orjson-3.9.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1c3cee5c23979deb8d1b82dc4cc49be59cccc0547999dbe9adb434bb7af11cf7"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a347d7b43cb609e780ff8d7b3107d4bcb5b6fd09c2702aa7bdf52f15ed09fa09"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:154fd67216c2ca38a2edb4089584504fbb6c0694b518b9020ad35ecc97252bb9"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ea3e63e61b4b0beeb08508458bdff2daca7a321468d3c4b320a758a2f554d31"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb0b0b2476f357eb2975ff040ef23978137aa674cd86204cfd15d2d17318588"}, - {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b9a20a03576c6b7022926f614ac5a6b0914486825eac89196adf3267c6489d"}, - {file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:915e22c93e7b7b636240c5a79da5f6e4e84988d699656c8e27f2ac4c95b8dcc0"}, - {file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f26fb3e8e3e2ee405c947ff44a3e384e8fa1843bc35830fe6f3d9a95a1147b6e"}, - {file = "orjson-3.9.7-cp312-none-win_amd64.whl", hash = "sha256:d8692948cada6ee21f33db5e23460f71c8010d6dfcfe293c9b96737600a7df78"}, - {file = "orjson-3.9.7-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7bab596678d29ad969a524823c4e828929a90c09e91cc438e0ad79b37ce41166"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63ef3d371ea0b7239ace284cab9cd00d9c92b73119a7c274b437adb09bda35e6"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f8fcf696bbbc584c0c7ed4adb92fd2ad7d153a50258842787bc1524e50d7081"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90fe73a1f0321265126cbba13677dcceb367d926c7a65807bd80916af4c17047"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45a47f41b6c3beeb31ac5cf0ff7524987cfcce0a10c43156eb3ee8d92d92bf22"}, - {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a2937f528c84e64be20cb80e70cea76a6dfb74b628a04dab130679d4454395c"}, - {file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b4fb306c96e04c5863d52ba8d65137917a3d999059c11e659eba7b75a69167bd"}, - {file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:410aa9d34ad1089898f3db461b7b744d0efcf9252a9415bbdf23540d4f67589f"}, - {file = "orjson-3.9.7-cp37-none-win32.whl", hash = "sha256:26ffb398de58247ff7bde895fe30817a036f967b0ad0e1cf2b54bda5f8dcfdd9"}, - {file = "orjson-3.9.7-cp37-none-win_amd64.whl", hash = "sha256:bcb9a60ed2101af2af450318cd89c6b8313e9f8df4e8fb12b657b2e97227cf08"}, - {file = "orjson-3.9.7-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5da9032dac184b2ae2da4bce423edff7db34bfd936ebd7d4207ea45840f03905"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7951af8f2998045c656ba8062e8edf5e83fd82b912534ab1de1345de08a41d2b"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8e59650292aa3a8ea78073fc84184538783966528e442a1b9ed653aa282edcf"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9274ba499e7dfb8a651ee876d80386b481336d3868cba29af839370514e4dce0"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca1706e8b8b565e934c142db6a9592e6401dc430e4b067a97781a997070c5378"}, - {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cc275cf6dcb1a248e1876cdefd3f9b5f01063854acdfd687ec360cd3c9712a"}, - {file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:11c10f31f2c2056585f89d8229a56013bc2fe5de51e095ebc71868d070a8dd81"}, - {file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cf334ce1d2fadd1bf3e5e9bf15e58e0c42b26eb6590875ce65bd877d917a58aa"}, - {file = "orjson-3.9.7-cp38-none-win32.whl", hash = "sha256:76a0fc023910d8a8ab64daed8d31d608446d2d77c6474b616b34537aa7b79c7f"}, - {file = "orjson-3.9.7-cp38-none-win_amd64.whl", hash = "sha256:7a34a199d89d82d1897fd4a47820eb50947eec9cda5fd73f4578ff692a912f89"}, - {file = "orjson-3.9.7-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e7e7f44e091b93eb39db88bb0cb765db09b7a7f64aea2f35e7d86cbf47046c65"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01d647b2a9c45a23a84c3e70e19d120011cba5f56131d185c1b78685457320bb"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0eb850a87e900a9c484150c414e21af53a6125a13f6e378cf4cc11ae86c8f9c5"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f4b0042d8388ac85b8330b65406c84c3229420a05068445c13ca28cc222f1f7"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd3e7aae977c723cc1dbb82f97babdb5e5fbce109630fbabb2ea5053523c89d3"}, - {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c616b796358a70b1f675a24628e4823b67d9e376df2703e893da58247458956"}, - {file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3ba725cf5cf87d2d2d988d39c6a2a8b6fc983d78ff71bc728b0be54c869c884"}, - {file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4891d4c934f88b6c29b56395dfc7014ebf7e10b9e22ffd9877784e16c6b2064f"}, - {file = "orjson-3.9.7-cp39-none-win32.whl", hash = "sha256:14d3fb6cd1040a4a4a530b28e8085131ed94ebc90d72793c59a713de34b60838"}, - {file = "orjson-3.9.7-cp39-none-win_amd64.whl", hash = "sha256:9ef82157bbcecd75d6296d5d8b2d792242afcd064eb1ac573f8847b52e58f677"}, - {file = "orjson-3.9.7.tar.gz", hash = "sha256:85e39198f78e2f7e054d296395f6c96f5e02892337746ef5b6a1bf3ed5910142"}, +python-versions = ">=3.8" +files = [ + {file = "orjson-3.9.10-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c18a4da2f50050a03d1da5317388ef84a16013302a5281d6f64e4a3f406aabc4"}, + {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5148bab4d71f58948c7c39d12b14a9005b6ab35a0bdf317a8ade9a9e4d9d0bd5"}, + {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cf7837c3b11a2dfb589f8530b3cff2bd0307ace4c301e8997e95c7468c1378e"}, + {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c62b6fa2961a1dcc51ebe88771be5319a93fd89bd247c9ddf732bc250507bc2b"}, + {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb3922a7a804755bbe6b5be9b312e746137a03600f488290318936c1a2d4dc"}, + {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1234dc92d011d3554d929b6cf058ac4a24d188d97be5e04355f1b9223e98bbe9"}, + {file = "orjson-3.9.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:06ad5543217e0e46fd7ab7ea45d506c76f878b87b1b4e369006bdb01acc05a83"}, + {file = "orjson-3.9.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4fd72fab7bddce46c6826994ce1e7de145ae1e9e106ebb8eb9ce1393ca01444d"}, + {file = "orjson-3.9.10-cp310-none-win32.whl", hash = "sha256:b5b7d4a44cc0e6ff98da5d56cde794385bdd212a86563ac321ca64d7f80c80d1"}, + {file = "orjson-3.9.10-cp310-none-win_amd64.whl", hash = "sha256:61804231099214e2f84998316f3238c4c2c4aaec302df12b21a64d72e2a135c7"}, + {file = "orjson-3.9.10-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cff7570d492bcf4b64cc862a6e2fb77edd5e5748ad715f487628f102815165e9"}, + {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8bc367f725dfc5cabeed1ae079d00369900231fbb5a5280cf0736c30e2adf7"}, + {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c812312847867b6335cfb264772f2a7e85b3b502d3a6b0586aa35e1858528ab1"}, + {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edd2856611e5050004f4722922b7b1cd6268da34102667bd49d2a2b18bafb81"}, + {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:674eb520f02422546c40401f4efaf8207b5e29e420c17051cddf6c02783ff5ca"}, + {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0dc4310da8b5f6415949bd5ef937e60aeb0eb6b16f95041b5e43e6200821fb"}, + {file = "orjson-3.9.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e99c625b8c95d7741fe057585176b1b8783d46ed4b8932cf98ee145c4facf499"}, + {file = "orjson-3.9.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ec6f18f96b47299c11203edfbdc34e1b69085070d9a3d1f302810cc23ad36bf3"}, + {file = "orjson-3.9.10-cp311-none-win32.whl", hash = "sha256:ce0a29c28dfb8eccd0f16219360530bc3cfdf6bf70ca384dacd36e6c650ef8e8"}, + {file = "orjson-3.9.10-cp311-none-win_amd64.whl", hash = "sha256:cf80b550092cc480a0cbd0750e8189247ff45457e5a023305f7ef1bcec811616"}, + {file = "orjson-3.9.10-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:602a8001bdf60e1a7d544be29c82560a7b49319a0b31d62586548835bbe2c862"}, + {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f295efcd47b6124b01255d1491f9e46f17ef40d3d7eabf7364099e463fb45f0f"}, + {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92af0d00091e744587221e79f68d617b432425a7e59328ca4c496f774a356071"}, + {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5a02360e73e7208a872bf65a7554c9f15df5fe063dc047f79738998b0506a14"}, + {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:858379cbb08d84fe7583231077d9a36a1a20eb72f8c9076a45df8b083724ad1d"}, + {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666c6fdcaac1f13eb982b649e1c311c08d7097cbda24f32612dae43648d8db8d"}, + {file = "orjson-3.9.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3fb205ab52a2e30354640780ce4587157a9563a68c9beaf52153e1cea9aa0921"}, + {file = "orjson-3.9.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7ec960b1b942ee3c69323b8721df2a3ce28ff40e7ca47873ae35bfafeb4555ca"}, + {file = "orjson-3.9.10-cp312-none-win_amd64.whl", hash = "sha256:3e892621434392199efb54e69edfff9f699f6cc36dd9553c5bf796058b14b20d"}, + {file = "orjson-3.9.10-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8b9ba0ccd5a7f4219e67fbbe25e6b4a46ceef783c42af7dbc1da548eb28b6531"}, + {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e2ecd1d349e62e3960695214f40939bbfdcaeaaa62ccc638f8e651cf0970e5f"}, + {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f433be3b3f4c66016d5a20e5b4444ef833a1f802ced13a2d852c637f69729c1"}, + {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4689270c35d4bb3102e103ac43c3f0b76b169760aff8bcf2d401a3e0e58cdb7f"}, + {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bd176f528a8151a6efc5359b853ba3cc0e82d4cd1fab9c1300c5d957dc8f48c"}, + {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a2ce5ea4f71681623f04e2b7dadede3c7435dfb5e5e2d1d0ec25b35530e277b"}, + {file = "orjson-3.9.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:49f8ad582da6e8d2cf663c4ba5bf9f83cc052570a3a767487fec6af839b0e777"}, + {file = "orjson-3.9.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2a11b4b1a8415f105d989876a19b173f6cdc89ca13855ccc67c18efbd7cbd1f8"}, + {file = "orjson-3.9.10-cp38-none-win32.whl", hash = "sha256:a353bf1f565ed27ba71a419b2cd3db9d6151da426b61b289b6ba1422a702e643"}, + {file = "orjson-3.9.10-cp38-none-win_amd64.whl", hash = "sha256:e28a50b5be854e18d54f75ef1bb13e1abf4bc650ab9d635e4258c58e71eb6ad5"}, + {file = "orjson-3.9.10-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ee5926746232f627a3be1cc175b2cfad24d0170d520361f4ce3fa2fd83f09e1d"}, + {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a73160e823151f33cdc05fe2cea557c5ef12fdf276ce29bb4f1c571c8368a60"}, + {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c338ed69ad0b8f8f8920c13f529889fe0771abbb46550013e3c3d01e5174deef"}, + {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5869e8e130e99687d9e4be835116c4ebd83ca92e52e55810962446d841aba8de"}, + {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2c1e559d96a7f94a4f581e2a32d6d610df5840881a8cba8f25e446f4d792df3"}, + {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a3a3a72c9811b56adf8bcc829b010163bb2fc308877e50e9910c9357e78521"}, + {file = "orjson-3.9.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7f8fb7f5ecf4f6355683ac6881fd64b5bb2b8a60e3ccde6ff799e48791d8f864"}, + {file = "orjson-3.9.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c943b35ecdf7123b2d81d225397efddf0bce2e81db2f3ae633ead38e85cd5ade"}, + {file = "orjson-3.9.10-cp39-none-win32.whl", hash = "sha256:fb0b361d73f6b8eeceba47cd37070b5e6c9de5beaeaa63a1cb35c7e1a73ef088"}, + {file = "orjson-3.9.10-cp39-none-win_amd64.whl", hash = "sha256:b90f340cb6397ec7a854157fac03f0c82b744abdd1c0941a024c3c29d1340aff"}, + {file = "orjson-3.9.10.tar.gz", hash = "sha256:9ebbdbd6a046c304b1845e96fbcc5559cd296b4dfd3ad2509e33c4d9ce07d6a1"}, ] [[package]] @@ -1764,14 +1693,14 @@ files = [ [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] @@ -1788,38 +1717,32 @@ files = [ [[package]] name = "platformdirs" -version = "4.0.0" +version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, - {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} - [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" -version = "1.2.0" +version = "1.3.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, ] -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] @@ -1839,7 +1762,6 @@ files = [ [package.dependencies] cfgv = ">=2.0.0" identify = ">=1.0.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" @@ -1976,7 +1898,6 @@ files = [ [package.dependencies] annotated-types = ">=0.4.0" -importlib-metadata = {version = "*", markers = "python_version == \"3.7\""} pydantic-core = "2.14.5" typing-extensions = ">=4.6.1" @@ -2131,18 +2052,18 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.2.1" +version = "10.5" description = "Extension pack for Python Markdown." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.2.1-py3-none-any.whl", hash = "sha256:bded105eb8d93f88f2f821f00108cb70cef1269db6a40128c09c5f48bfc60ea4"}, - {file = "pymdown_extensions-10.2.1.tar.gz", hash = "sha256:d0c534b4a5725a4be7ccef25d65a4c97dba58b54ad7c813babf0eb5ba9c81591"}, + {file = "pymdown_extensions-10.5-py3-none-any.whl", hash = "sha256:1f0ca8bb5beff091315f793ee17683bc1390731f6ac4c5eb01e27464b80fe879"}, + {file = "pymdown_extensions-10.5.tar.gz", hash = "sha256:1b60f1e462adbec5a1ed79dac91f666c9c0d241fa294de1989f29d20096cfd0b"}, ] [package.dependencies] -markdown = ">=3.2" +markdown = ">=3.5" pyyaml = "*" [package.extras] @@ -2179,7 +2100,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" @@ -2202,7 +2122,6 @@ files = [ [package.dependencies] pytest = ">=7.0.0" -typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""} [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -2470,20 +2389,20 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "68.0.0" +version = "69.0.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, - {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, + {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, + {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -2574,7 +2493,6 @@ files = [ [package.dependencies] greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [package.extras] aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] @@ -2637,18 +2555,17 @@ test = ["coverage[toml]", "pytest", "pytest-cov"] [[package]] name = "stevedore" -version = "3.5.2" +version = "5.1.0" description = "Manage dynamic plugins for Python applications" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "stevedore-3.5.2-py3-none-any.whl", hash = "sha256:fa2630e3d0ad3e22d4914aff2501445815b9a4467a6edc49387c667a38faf5bf"}, - {file = "stevedore-3.5.2.tar.gz", hash = "sha256:cf99f41fc0d5a4f185ca4d3d42b03be9011b0a1ec1a4ea1a282be1b4b306dcc2"}, + {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, + {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, ] [package.dependencies] -importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""} pbr = ">=2.0.0,<2.1.0 || >2.1.0" [[package]] @@ -2663,57 +2580,6 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -[[package]] -name = "typed-ast" -version = "1.5.5" -description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, - {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, - {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, - {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, - {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, - {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, - {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, - {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, - {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, - {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, - {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, - {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, - {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, - {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, - {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, - {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, - {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, - {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, - {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, - {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, - {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, - {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, - {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, - {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, - {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, - {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, - {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, - {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, - {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, - {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, - {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, - {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, - {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, - {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, - {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, - {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, - {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, - {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, - {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, - {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, - {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, -] - [[package]] name = "types-aiofiles" version = "23.2.0.0" @@ -2839,31 +2705,30 @@ files = [ [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] [[package]] name = "urllib3" -version = "2.0.7" +version = "2.1.0" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2882,7 +2747,6 @@ files = [ [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""} platformdirs = ">=3.9.1,<5" [package.extras] @@ -2994,19 +2858,19 @@ test = ["gevent (>=20.6.2)"] [[package]] name = "zipp" -version = "3.15.0" +version = "3.17.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, - {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [extras] aiopg = ["aiopg", "psycopg2-binary"] @@ -3020,5 +2884,5 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" -python-versions = "^3.7.0" -content-hash = "4d0a640b3285716ffdad96bfe0ede753fce2a7de8ae978205c8d22f4808b7dd3" +python-versions = "^3.8.0" +content-hash = "e3ec7fe7f8ab6b202e1273d2d2edcd76cbb2b65c9ed129e64a7b420fb58f6445" diff --git a/pyproject.toml b/pyproject.toml index 7ead1c8fb..b5a91e812 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,16 +32,16 @@ classifiers = [ "Topic :: Internet :: WWW/HTTP", "Framework :: AsyncIO", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3 :: Only", ] [tool.poetry.dependencies] -python = "^3.7.0" +python = "^3.8.0" databases = ">=0.3.2,!=0.5.0,!=0.5.1,!=0.5.2,!=0.5.3,<0.6.3" pydantic = ">=v2.5.2" SQLAlchemy = ">=1.3.18,<1.4.42" @@ -76,7 +76,7 @@ pytest = "^7.4.0" pytest-cov = "^4.0.0" codecov = "^2.1.13" pytest-asyncio = "^0.21.0" -fastapi = ">=0.100.0-beta1" +fastapi = ">=0.105.0" flake8 = "^3.9.2" flake8-black = "^0.3.6" flake8-bugbear = "^23.3.12" diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index 9790386aa..380d0424a 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -4,6 +4,7 @@ from collections import Counter import databases +import pydantic import pytest import sqlalchemy as sa from sqlalchemy import create_engine @@ -160,7 +161,7 @@ class Bus2(Car2): class ImmutablePerson(Person): model_config = dict( - allow_mutation = False, + frozen = True, validate_assignment = False) @@ -477,11 +478,11 @@ async def test_inheritance_with_multi_relation(): def test_custom_config(): # Custom config inherits defaults - assert getattr(ImmutablePerson.model_config, "orm_mode") is True + assert ImmutablePerson.model_config["from_attributes"] is True # Custom config can override defaults - assert getattr(ImmutablePerson.model_config, "validate_assignment") is False + assert ImmutablePerson.model_config["validate_assignment"] is False sam = ImmutablePerson(name="Sam") - with pytest.raises(TypeError): + with pytest.raises(pydantic.ValidationError): sam.name = "Not Sam" From 7e40719c404b87b5fe44331efd2715fea7bb61c2 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 15 Dec 2023 20:52:53 +0100 Subject: [PATCH 10/95] WIP fix tests checking pydantic schema, fix excluding parent fields, failing 21/442 --- ormar/models/helpers/pydantic.py | 1 + .../test_geting_pydantic_models.py | 29 ++++++++++++++----- .../test_nested_models_pydantic.py | 6 ++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index f5dc6c647..ec2caf714 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -137,3 +137,4 @@ def remove_excluded_parent_fields(model: Type["Model"]) -> None: model.model_fields = { k: v for k, v in model.model_fields.items() if k not in excludes } + model.model_rebuild(force=True) diff --git a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py index d18f8b1e0..cc1f8a23e 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py +++ b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py @@ -5,6 +5,8 @@ import sqlalchemy from typing import ForwardRef +from pydantic_core import PydanticUndefined + import ormar from tests.settings import DATABASE_URL @@ -76,16 +78,17 @@ def test_getting_pydantic_model(): assert PydanticCategory.model_fields["name"].is_required() assert PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["name"]["schema"]["type"] == "str" - assert PydanticCategory.model_fields["name"].default in [None, Ellipsis] + assert PydanticCategory.model_fields["name"].default == PydanticUndefined - PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"][ + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ "items_schema" ]["cls"] - assert PydanticCategory.model_fields["items"].outer_type_ == List[PydanticItem] + assert PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"]["type"] == "list" + assert PydanticCategory.model_fields["items"].annotation == Optional[List[PydanticItem]] assert issubclass(PydanticItem, pydantic.BaseModel) assert not PydanticItem.model_fields["name"].is_required() assert PydanticItem.model_fields["name"].default == "test" - assert issubclass(PydanticItem.model_fields["name"].outer_type_, str) + assert PydanticItem.model_fields["name"].annotation == Optional[str] assert "category" not in PydanticItem.model_fields @@ -238,8 +241,14 @@ def test_getting_pydantic_model_mutual_rels(): assert len(MutualAPydantic.model_fields) == 3 assert set(MutualAPydantic.model_fields.keys()) == {"id", "mutual_b", "mutuals_b"} - MutualB1 = MutualAPydantic.model_fields["mutual_b"].type_ - MutualB2 = MutualAPydantic.model_fields["mutuals_b"].type_ + mutual_ref_1 = MutualAPydantic.__pydantic_core_schema__["schema"]["schema"]["fields"]["mutual_b"]["schema"]["schema"]["schema"]["schema_ref"] + MutualB1 = next( + (x for x in MutualAPydantic.__pydantic_core_schema__["definitions"] if x["ref"] == mutual_ref_1) + )["cls"] + mutual_ref_2 = MutualAPydantic.__pydantic_core_schema__["schema"]["schema"]["fields"]["mutuals_b"]["schema"]["schema"]["schema"]["items_schema"]["schema_ref"] + MutualB2 = next( + (x for x in MutualAPydantic.__pydantic_core_schema__["definitions"] if x["ref"] == mutual_ref_2) + )["cls"] assert len(MutualB1.model_fields) == 2 assert set(MutualB1.model_fields.keys()) == {"id", "name"} assert len(MutualB2.model_fields) == 2 @@ -252,8 +261,12 @@ def test_getting_pydantic_model_mutual_rels_exclude(): assert len(MutualAPydantic.model_fields) == 3 assert set(MutualAPydantic.model_fields.keys()) == {"id", "mutual_b", "mutuals_b"} - MutualB1 = MutualAPydantic.model_fields["mutual_b"].type_ - MutualB2 = MutualAPydantic.model_fields["mutuals_b"].type_ + MutualB1 = MutualAPydantic.__pydantic_core_schema__["schema"]["fields"]["mutual_b"]["schema"][ + "schema" + ]["schema"]["cls"] + MutualB2 = MutualAPydantic.__pydantic_core_schema__["schema"]["fields"]["mutuals_b"]["schema"][ + "schema" + ]["schema"]["items_schema"]["cls"] assert len(MutualB1.model_fields) == 1 assert set(MutualB1.model_fields.keys()) == {"id"} diff --git a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py index c40ec1d78..8c3c3175e 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py @@ -47,9 +47,9 @@ class TicketPackage(ormar.Model): def test_have_proper_children(): TicketPackageOut = TicketPackage.get_pydantic(exclude={"ticket"}) - assert "package" in TicketPackageOut.__fields__ - PydanticPackage = TicketPackageOut.__fields__["package"].type_ - assert "library" in PydanticPackage.__fields__ + assert "package" in TicketPackageOut.model_fields + PydanticPackage = TicketPackageOut.__pydantic_core_schema__["schema"]["fields"]["package"]["schema"]["schema"]["schema"]["cls"] + assert "library" in PydanticPackage.model_fields def test_casts_properly(): From 6809173ceaaac2dcb8aeca9217747f58b1c51b39 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 15 Dec 2023 21:10:47 +0100 Subject: [PATCH 11/95] WIP some missed files --- ormar/models/helpers/pydantic.py | 4 +- .../test_geting_pydantic_models.py | 133 +++++++++++------- .../test_nested_models_pydantic.py | 5 +- 3 files changed, 92 insertions(+), 50 deletions(-) diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index ec2caf714..d317a4710 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -32,7 +32,9 @@ def create_pydantic_field( :param model_field: relation field from which through model is extracted :type model_field: ManyToManyField class """ - model_field.through.model_fields[field_name] = FieldInfo.from_annotated_attribute(annotation=model, default=None) + model_field.through.model_fields[field_name] = FieldInfo.from_annotated_attribute( + annotation=model, default=None + ) model_field.through.model_rebuild(force=True) diff --git a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py index cc1f8a23e..fffac628f 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py +++ b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py @@ -71,20 +71,35 @@ def test_getting_pydantic_model(): assert not PydanticCategory.model_fields["id"].is_required() assert ( - PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["id"]["schema"]["schema"]["schema"]["type"] + PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["id"]["schema"][ + "schema" + ]["schema"]["type"] == "int" ) assert PydanticCategory.model_fields["id"].default is None assert PydanticCategory.model_fields["name"].is_required() - assert PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["name"]["schema"]["type"] == "str" + assert ( + PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["name"]["schema"][ + "type" + ] + == "str" + ) assert PydanticCategory.model_fields["name"].default == PydanticUndefined - PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ - "items_schema" - ]["cls"] - assert PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"]["type"] == "list" - assert PydanticCategory.model_fields["items"].annotation == Optional[List[PydanticItem]] + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][ + "items" + ]["schema"]["schema"]["schema"]["items_schema"]["cls"] + assert ( + PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"][ + "schema" + ]["schema"]["schema"]["type"] + == "list" + ) + assert ( + PydanticCategory.model_fields["items"].annotation + == Optional[List[PydanticItem]] + ) assert issubclass(PydanticItem, pydantic.BaseModel) assert not PydanticItem.model_fields["name"].is_required() assert PydanticItem.model_fields["name"].default == "test" @@ -119,9 +134,9 @@ def test_getting_pydantic_model_nested_include_set(): PydanticCategory = Category.get_pydantic(include={"id", "items__id"}) assert len(PydanticCategory.model_fields) == 2 assert "name" not in PydanticCategory.model_fields - PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ - "items_schema" - ]["cls"] + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][ + "items" + ]["schema"]["schema"]["schema"]["items_schema"]["cls"] assert len(PydanticItem.model_fields) == 1 assert "id" in PydanticItem.model_fields @@ -130,9 +145,9 @@ def test_getting_pydantic_model_nested_include_dict(): PydanticCategory = Category.get_pydantic(include={"id": ..., "items": {"id"}}) assert len(PydanticCategory.model_fields) == 2 assert "name" not in PydanticCategory.model_fields - PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ - "items_schema" - ]["cls"] + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][ + "items" + ]["schema"]["schema"]["schema"]["items_schema"]["cls"] assert len(PydanticItem.model_fields) == 1 assert "id" in PydanticItem.model_fields @@ -141,20 +156,22 @@ def test_getting_pydantic_model_nested_include_nested_dict(): PydanticCategory = Category.get_pydantic(include={"id": ..., "items": {"id": ...}}) assert len(PydanticCategory.model_fields) == 2 assert "name" not in PydanticCategory.model_fields - PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ - "items_schema" - ]["cls"] + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][ + "items" + ]["schema"]["schema"]["schema"]["items_schema"]["cls"] assert len(PydanticItem.model_fields) == 1 assert "id" in PydanticItem.model_fields def test_getting_pydantic_model_include_exclude(): - PydanticCategory = Category.get_pydantic(include={"id": ..., "items": {"id", "name"}}, exclude={"items__name"}) + PydanticCategory = Category.get_pydantic( + include={"id": ..., "items": {"id", "name"}}, exclude={"items__name"} + ) assert len(PydanticCategory.model_fields) == 2 assert "name" not in PydanticCategory.model_fields - PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"]["schema"]["schema"]["schema"][ - "items_schema" - ]["cls"] + PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][ + "items" + ]["schema"]["schema"]["schema"]["items_schema"]["cls"] assert len(PydanticItem.model_fields) == 1 assert "id" in PydanticItem.model_fields @@ -163,9 +180,9 @@ def test_getting_pydantic_model_exclude(): PydanticItem = Item.get_pydantic(exclude={"category__name"}) assert len(PydanticItem.model_fields) == 3 assert "category" in PydanticItem.model_fields - PydanticCategory = PydanticItem.__pydantic_core_schema__["schema"]["fields"]["category"]["schema"]["schema"][ - "schema" - ]["cls"] + PydanticCategory = PydanticItem.__pydantic_core_schema__["schema"]["fields"][ + "category" + ]["schema"]["schema"]["schema"]["cls"] assert len(PydanticCategory.model_fields) == 1 assert "name" not in PydanticCategory.model_fields @@ -175,9 +192,9 @@ def test_getting_pydantic_model_exclude_dict(): assert len(PydanticItem.model_fields) == 2 assert "category" in PydanticItem.model_fields assert "id" not in PydanticItem.model_fields - PydanticCategory = PydanticItem.__pydantic_core_schema__["schema"]["fields"]["category"]["schema"]["schema"][ - "schema" - ]["cls"] + PydanticCategory = PydanticItem.__pydantic_core_schema__["schema"]["fields"][ + "category" + ]["schema"]["schema"]["schema"]["cls"] assert len(PydanticCategory.model_fields) == 1 assert "name" not in PydanticCategory.model_fields @@ -191,20 +208,28 @@ def test_getting_pydantic_model_self_ref(): "parent", "children", } - inner_self_ref_id = PydanticSelfRef.__pydantic_core_schema__["schema"]["schema"]["fields"]["parent"]["schema"][ - "schema" - ]["schema"]["schema_ref"] + inner_self_ref_id = PydanticSelfRef.__pydantic_core_schema__["schema"]["schema"][ + "fields" + ]["parent"]["schema"]["schema"]["schema"]["schema_ref"] InnerSelf = next( - (x for x in PydanticSelfRef.__pydantic_core_schema__["definitions"] if x["ref"] == inner_self_ref_id) + ( + x + for x in PydanticSelfRef.__pydantic_core_schema__["definitions"] + if x["ref"] == inner_self_ref_id + ) )["cls"] assert len(InnerSelf.model_fields) == 2 assert set(InnerSelf.model_fields.keys()) == {"id", "name"} - inner_self_ref_id2 = PydanticSelfRef.__pydantic_core_schema__["schema"]["schema"]["fields"]["children"]["schema"][ - "schema" - ]["schema"]["items_schema"]["schema_ref"] + inner_self_ref_id2 = PydanticSelfRef.__pydantic_core_schema__["schema"]["schema"][ + "fields" + ]["children"]["schema"]["schema"]["schema"]["items_schema"]["schema_ref"] InnerSelf2 = next( - (x for x in PydanticSelfRef.__pydantic_core_schema__["definitions"] if x["ref"] == inner_self_ref_id2) + ( + x + for x in PydanticSelfRef.__pydantic_core_schema__["definitions"] + if x["ref"] == inner_self_ref_id2 + ) )["cls"] assert len(InnerSelf2.model_fields) == 2 assert set(InnerSelf2.model_fields.keys()) == {"id", "name"} @@ -220,16 +245,16 @@ def test_getting_pydantic_model_self_ref_exclude(): "children", } - InnerSelf = PydanticSelfRef.__pydantic_core_schema__["schema"]["fields"]["parent"]["schema"][ + InnerSelf = PydanticSelfRef.__pydantic_core_schema__["schema"]["fields"]["parent"][ "schema" - ]["schema"]["cls"] + ]["schema"]["schema"]["cls"] assert len(InnerSelf.model_fields) == 2 assert set(InnerSelf.model_fields.keys()) == {"id", "name"} # PydanticSelfRefChildren = PydanticSelfRef.model_fields["children"].type_ - PydanticSelfRefChildren = PydanticSelfRef.__pydantic_core_schema__["schema"]["fields"]["children"]["schema"][ - "schema" - ]["schema"]["items_schema"]["cls"] + PydanticSelfRefChildren = PydanticSelfRef.__pydantic_core_schema__["schema"][ + "fields" + ]["children"]["schema"]["schema"]["schema"]["items_schema"]["cls"] assert len(PydanticSelfRefChildren.model_fields) == 1 assert set(PydanticSelfRefChildren.model_fields.keys()) == {"id"} assert PydanticSelfRef != PydanticSelfRefChildren @@ -241,13 +266,25 @@ def test_getting_pydantic_model_mutual_rels(): assert len(MutualAPydantic.model_fields) == 3 assert set(MutualAPydantic.model_fields.keys()) == {"id", "mutual_b", "mutuals_b"} - mutual_ref_1 = MutualAPydantic.__pydantic_core_schema__["schema"]["schema"]["fields"]["mutual_b"]["schema"]["schema"]["schema"]["schema_ref"] + mutual_ref_1 = MutualAPydantic.__pydantic_core_schema__["schema"]["schema"][ + "fields" + ]["mutual_b"]["schema"]["schema"]["schema"]["schema_ref"] MutualB1 = next( - (x for x in MutualAPydantic.__pydantic_core_schema__["definitions"] if x["ref"] == mutual_ref_1) + ( + x + for x in MutualAPydantic.__pydantic_core_schema__["definitions"] + if x["ref"] == mutual_ref_1 + ) )["cls"] - mutual_ref_2 = MutualAPydantic.__pydantic_core_schema__["schema"]["schema"]["fields"]["mutuals_b"]["schema"]["schema"]["schema"]["items_schema"]["schema_ref"] + mutual_ref_2 = MutualAPydantic.__pydantic_core_schema__["schema"]["schema"][ + "fields" + ]["mutuals_b"]["schema"]["schema"]["schema"]["items_schema"]["schema_ref"] MutualB2 = next( - (x for x in MutualAPydantic.__pydantic_core_schema__["definitions"] if x["ref"] == mutual_ref_2) + ( + x + for x in MutualAPydantic.__pydantic_core_schema__["definitions"] + if x["ref"] == mutual_ref_2 + ) )["cls"] assert len(MutualB1.model_fields) == 2 assert set(MutualB1.model_fields.keys()) == {"id", "name"} @@ -261,12 +298,12 @@ def test_getting_pydantic_model_mutual_rels_exclude(): assert len(MutualAPydantic.model_fields) == 3 assert set(MutualAPydantic.model_fields.keys()) == {"id", "mutual_b", "mutuals_b"} - MutualB1 = MutualAPydantic.__pydantic_core_schema__["schema"]["fields"]["mutual_b"]["schema"][ - "schema" - ]["schema"]["cls"] - MutualB2 = MutualAPydantic.__pydantic_core_schema__["schema"]["fields"]["mutuals_b"]["schema"][ + MutualB1 = MutualAPydantic.__pydantic_core_schema__["schema"]["fields"]["mutual_b"][ "schema" - ]["schema"]["items_schema"]["cls"] + ]["schema"]["schema"]["cls"] + MutualB2 = MutualAPydantic.__pydantic_core_schema__["schema"]["fields"][ + "mutuals_b" + ]["schema"]["schema"]["schema"]["items_schema"]["cls"] assert len(MutualB1.model_fields) == 1 assert set(MutualB1.model_fields.keys()) == {"id"} diff --git a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py index 8c3c3175e..bee065a8e 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py @@ -13,6 +13,7 @@ database=database, ) + class Library(ormar.Model): ormar_config = base_ormar_config.copy() @@ -48,7 +49,9 @@ class TicketPackage(ormar.Model): def test_have_proper_children(): TicketPackageOut = TicketPackage.get_pydantic(exclude={"ticket"}) assert "package" in TicketPackageOut.model_fields - PydanticPackage = TicketPackageOut.__pydantic_core_schema__["schema"]["fields"]["package"]["schema"]["schema"]["schema"]["cls"] + PydanticPackage = TicketPackageOut.__pydantic_core_schema__["schema"]["fields"][ + "package" + ]["schema"]["schema"]["schema"]["cls"] assert "library" in PydanticPackage.model_fields From aacfebbdf44118c6ead077436167175b2c44b758 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 15 Dec 2023 21:45:49 +0100 Subject: [PATCH 12/95] WIP - fix validators inheritance and fix validators in generated pydantic, failing 17/442 --- ormar/models/mixins/pydantic_mixin.py | 66 +++++++++++-------- .../test_validators_are_inherited.py | 31 ++++----- .../test_validators_in_generated_pydantic.py | 14 ++-- 3 files changed, 59 insertions(+), 52 deletions(-) diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index 6f222c851..599f90106 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -66,7 +66,9 @@ def _convert_ormar_to_pydantic( fields_dict: Dict[str, Any] = dict() defaults: Dict[str, Any] = dict() fields_to_process = cls._get_not_excluded_fields( - fields={*cls.ormar_config.model_fields.keys()}, include=include, exclude=exclude + fields={*cls.ormar_config.model_fields.keys()}, + include=include, + exclude=exclude, ) fields_to_process.sort( key=lambda x: list(cls.ormar_config.model_fields.keys()).index(x) @@ -131,28 +133,40 @@ def _copy_field_validators(cls, model: Type[pydantic.BaseModel]) -> None: """ Copy field validators from ormar model to generated pydantic model. """ - # TODO: FIX THIS - # for field_name, field in model.model_fields.items(): - # if ( - # field_name not in cls.model_fields - # or cls.ormar_config.model_fields[field_name].is_relation - # ): - # continue - # validators = cls.model_fields[field_name].validators - # already_attached = [ - # validator.__wrapped__ for validator in field.validators # type: ignore - # ] - # validators_to_copy = [ - # validator - # for validator in validators - # if validator.__wrapped__ not in already_attached # type: ignore - # ] - # field.validators.extend(copy.deepcopy(validators_to_copy)) - # class_validators = cls.model_fields[field_name].class_validators - # field.class_validators.update(copy.deepcopy(class_validators)) - # field.pre_validators = copy.deepcopy( - # cls.model_fields[field_name].pre_validators - # ) - # field.post_validators = copy.deepcopy( - # cls.model_fields[field_name].post_validators - # ) + filed_names = list(model.model_fields.keys()) + cls.copy_selected_validators_type( + model=model, fields=filed_names, validator_type="field_validators" + ) + cls.copy_selected_validators_type( + model=model, fields=filed_names, validator_type="validators" + ) + + class_validators = cls.__pydantic_decorators__.root_validators + model.__pydantic_decorators__.root_validators.update( + copy.deepcopy(class_validators) + ) + model_validators = cls.__pydantic_decorators__.model_validators + model.__pydantic_decorators__.model_validators.update( + copy.deepcopy(model_validators) + ) + model.model_rebuild(force=True) + + @classmethod + def copy_selected_validators_type( + cls, model: Type[pydantic.BaseModel], fields: List[str], validator_type: str + ) -> None: + """ + Copy field validators from ormar model to generated pydantic model. + """ + validators = getattr(cls.__pydantic_decorators__, validator_type) + for name, decorator in validators.items(): + if any(field_name in decorator.info.fields for field_name in fields): + copied_decorator = copy.deepcopy(decorator) + copied_decorator.info.fields = [ + field_name + for field_name in decorator.info.fields + if field_name in fields + ] + getattr(model.__pydantic_decorators__, validator_type)[ + name + ] = copied_decorator diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py index f9c1d327e..9e1aac75d 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py @@ -1,10 +1,9 @@ import enum import databases -import pydantic import pytest import sqlalchemy -from pydantic import ValidationError +from pydantic import ValidationError, field_validator import ormar from tests.settings import DATABASE_URL @@ -20,11 +19,16 @@ class BaseModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract = True - ) + ormar_config = ormar.OrmarConfig(abstract=True) id: int = ormar.Integer(primary_key=True) + str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) + + @field_validator("str_field") + def validate_str_field(cls, v): + if " " not in v: + raise ValueError("must contain a space") + return v class EnumExample(str, enum.Enum): @@ -34,18 +38,9 @@ class EnumExample(str, enum.Enum): class ModelExample(BaseModel): - ormar_config = base_ormar_config.copy(tablename = "examples") + ormar_config = base_ormar_config.copy(tablename="examples") - str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) - enum_field: str = ormar.String( - max_length=1, nullable=False, choices=list(EnumExample) - ) - - @pydantic.validator("str_field") - def validate_str_field(cls, v): - if " " not in v: - raise ValueError("must contain a space") - return v + enum_field: str = ormar.Enum(enum_class=EnumExample, nullable=False) ModelExampleCreate = ModelExample.get_pydantic(exclude={"id"}) @@ -58,7 +53,7 @@ def test_ormar_validator(): assert "must contain a space" in str(e) with pytest.raises(ValidationError) as e: ModelExample(str_field="a aaaaaaa", enum_field="Z") - assert "not in allowed choices" in str(e) + assert "Input should be 'A', 'B' or 'C'" in str(e) def test_pydantic_validator(): @@ -68,4 +63,4 @@ def test_pydantic_validator(): assert "must contain a space" in str(e) with pytest.raises(ValidationError) as e: ModelExampleCreate(str_field="a aaaaaaa", enum_field="Z") - assert "not in allowed choices" in str(e) + assert "Input should be 'A', 'B' or 'C'" in str(e) diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py index 5439c0f29..4c3344085 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py @@ -28,16 +28,14 @@ class EnumExample(str, enum.Enum): class ModelExample(ormar.Model): ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, - tablename = "examples", + database=database, + metadata=metadata, + tablename="examples", ) id: int = ormar.Integer(primary_key=True) str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) - enum_field: str = ormar.String( - max_length=1, nullable=False, choices=list(EnumExample) - ) + enum_field: str = ormar.Enum(nullable=False, enum_class=EnumExample) @pydantic.validator("str_field") def validate_str_field(cls, v): @@ -56,7 +54,7 @@ def test_ormar_validator(): assert "must contain a space" in str(e) with pytest.raises(ValidationError) as e: ModelExample(str_field="a aaaaaaa", enum_field="Z") - assert "not in allowed choices" in str(e) + assert "Input should be 'A', 'B' or 'C'" in str(e) def test_pydantic_validator(): @@ -66,4 +64,4 @@ def test_pydantic_validator(): assert "must contain a space" in str(e) with pytest.raises(ValidationError) as e: ModelExampleCreate(str_field="a aaaaaaa", enum_field="Z") - assert "not in allowed choices" in str(e) + assert "Input should be 'A', 'B' or 'C'" in str(e) From 0a6ca89b759ff54e750bf8135085aef7c093c067 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 15 Dec 2023 23:25:33 +0100 Subject: [PATCH 13/95] WIP - fix through models setting - only on reverse side of relation, but always on reverse side, failing 15/442 --- ormar/models/helpers/pydantic.py | 6 +- ormar/models/mixins/save_mixin.py | 6 +- ormar/models/newbasemodel.py | 61 +++++++++++++++++-- .../test_complex_relation_tree_performance.py | 9 --- .../test_dumping_model_to_dict.py | 4 +- 5 files changed, 69 insertions(+), 17 deletions(-) diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index d317a4710..23372434c 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -33,8 +33,12 @@ def create_pydantic_field( :type model_field: ManyToManyField class """ model_field.through.model_fields[field_name] = FieldInfo.from_annotated_attribute( - annotation=model, default=None + annotation=Optional[model], default=None ) + # model.model_fields[model_field.through.get_name()] = FieldInfo.from_annotated_attribute( + # annotation=Optional[model_field.through], default=None + # ) + # model.model_rebuild(force=True) model_field.through.model_rebuild(force=True) diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index 1608d9a97..321828800 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -279,7 +279,11 @@ def _extract_pydantic_fields(cls): if cls.__pydantic_core_schema__["type"] == "model": return cls.__pydantic_core_schema__["schema"]["fields"] elif cls.__pydantic_core_schema__["type"] == "definitions": - return cls.__pydantic_core_schema__["schema"]["schema"]["fields"] + main_schema = cls.__pydantic_core_schema__["schema"] + if "schema_ref" in main_schema: + reference_id = main_schema["schema_ref"] + return next(ref for ref in cls.__pydantic_core_schema__["definitions"] if ref["ref"] == reference_id)["schema"]["fields"] + return main_schema["schema"]["fields"] @staticmethod async def _upsert_model( diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index ff196856b..e1bbf5722 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -626,19 +626,62 @@ def _extract_nested_models_from_list( result = [] for model in models: try: - result.append( - model.dict( + model_dict = model.dict( relation_map=relation_map, include=include, exclude=exclude, exclude_primary_keys=exclude_primary_keys, exclude_through_models=exclude_through_models, ) + model.populate_through_models( + model=model, + model_dict=model_dict, + include=include, + exclude=exclude, + relation_map=relation_map, ) + result.append(model_dict) except ReferenceError: # pragma no cover continue return result + @staticmethod + def populate_through_models( + model: "Model", + model_dict: Dict, + include: Union[Set, Dict], + exclude: Union[Set, Dict], + relation_map: Dict = None, + ) -> None: + """ + Populates through models with values from dict representation. + + :param model: model to populate through models + :type model: Model + :param values: dict representation of the model + :type values: Dict + :return: None + :rtype: None + """ + if include and isinstance(include, Set): + include = translate_list_to_dict(include) + if exclude and isinstance(exclude, Set): + exclude = translate_list_to_dict(exclude) + models_to_populate = model._get_not_excluded_fields( + fields=model.extract_through_names(), + include=include, + exclude=exclude + ) + for through_model in models_to_populate: + through_field = model.ormar_config.model_fields[through_model] + if through_field.related_name in relation_map: + continue + through_instance = getattr(model, through_model) + if through_instance: + model_dict[through_model] = through_instance.dict() + else: + model_dict[through_model] = None + @classmethod def _skip_ellipsis( cls, items: Union[Set, Dict, None], key: str, default_return: Any = None @@ -723,7 +766,7 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 ) elif nested_model is not None: - dict_instance[field] = nested_model.dict( + model_dict = nested_model.dict( relation_map=self._skip_ellipsis( relation_map, field, default_return=dict() ), @@ -732,6 +775,16 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 exclude_primary_keys=exclude_primary_keys, exclude_through_models=exclude_through_models, ) + nested_model.populate_through_models( + model=nested_model, + model_dict=model_dict, + include=self._convert_all(self._skip_ellipsis(include, field)), + exclude=self._convert_all(self._skip_ellipsis(exclude, field)), + relation_map=self._skip_ellipsis( + relation_map, field, default_return=dict() + ), + ) + dict_instance[field] = model_dict else: dict_instance[field] = None except ReferenceError: @@ -759,7 +812,7 @@ def dict( # type: ignore # noqa A003 Nested models are also parsed to dictionaries. - Additionally fields decorated with @property_field are also added. + Additionally, fields decorated with @property_field are also added. :param exclude_through_models: flag to exclude through models from dict :type exclude_through_models: bool diff --git a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py index 86439203d..470b15730 100644 --- a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py +++ b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py @@ -346,9 +346,6 @@ async def test_very_complex_relation_map(): "data": {}, "tag": { "id": 18, - "taglabel": None, - "tagcommit": None, - "tagissue": None, }, "changelogs": [], }, @@ -359,9 +356,6 @@ async def test_very_complex_relation_map(): "data": {}, "tag": { "id": 17, - "taglabel": None, - "tagcommit": None, - "tagissue": None, }, "changelogs": [], }, @@ -372,9 +366,6 @@ async def test_very_complex_relation_map(): "data": {}, "tag": { "id": 12, - "taglabel": None, - "tagcommit": None, - "tagissue": None, }, "changelogs": [], }, diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index c5fc65b84..9a8783f6b 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -159,7 +159,7 @@ def test_dumping_dict_without_primary_keys(sample_data): "email": "test@test.com", "first_name": "Anna", "password": "ijacids7^*&", - "roles": [{"name": "User"}, {"name": "Admin"}], + "roles": [{"name": "User", 'userrole': None}, {"name": "Admin", 'userrole': None}], }, "name": "M16", } @@ -170,7 +170,7 @@ def test_dumping_dict_without_primary_keys(sample_data): "email": "test@test.com", "first_name": "Anna", "password": "ijacids7^*&", - "roles": [{"name": "User"}, {"name": "Admin"}], + "roles": [{"name": "User", 'userrole': None}, {"name": "Admin", 'userrole': None}], }, "name": "Teddy Bear", } From fdb0ad9b16c327ce38c8df4de33b2f280408e4a8 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 15 Dec 2023 23:25:55 +0100 Subject: [PATCH 14/95] WIP - fix through models setting - only on reverse side of relation, but always on reverse side, failing 15/442 --- ormar/models/mixins/save_mixin.py | 16 +++++++++++++--- .../test_dumping_model_to_dict.py | 14 +++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index 321828800..9fff1048b 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -267,10 +267,16 @@ def _build_individual_schema_validator(cls) -> Any: field_validators = {} for key, field in cls._extract_pydantic_fields().items(): if cls.__pydantic_core_schema__["type"] == "definitions": - schema = {"type": "definitions", "schema": field["schema"], "definitions": cls.__pydantic_core_schema__["definitions"]} + schema = { + "type": "definitions", + "schema": field["schema"], + "definitions": cls.__pydantic_core_schema__["definitions"], + } else: schema = field["schema"] - field_validators[key] = create_schema_validator(schema, cls, cls.__module__, cls.__qualname__,'BaseModel') + field_validators[key] = create_schema_validator( + schema, cls, cls.__module__, cls.__qualname__, "BaseModel" + ) cls.__ormar_fields_validators__ = field_validators return cls.__ormar_fields_validators__ @@ -282,7 +288,11 @@ def _extract_pydantic_fields(cls): main_schema = cls.__pydantic_core_schema__["schema"] if "schema_ref" in main_schema: reference_id = main_schema["schema_ref"] - return next(ref for ref in cls.__pydantic_core_schema__["definitions"] if ref["ref"] == reference_id)["schema"]["fields"] + return next( + ref + for ref in cls.__pydantic_core_schema__["definitions"] + if ref["ref"] == reference_id + )["schema"]["fields"] return main_schema["schema"]["fields"] @staticmethod diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index 9a8783f6b..65b1aa53c 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -131,7 +131,9 @@ def test_dumping_to_dict_exclude_nested_dict(sample_data): def test_dumping_to_dict_exclude_and_include_nested_dict(sample_data): item1, item2 = sample_data - dict1 = item2.dict(exclude={"category": {"tier": {"name"}}}, include={"name", "category"}) + dict1 = item2.dict( + exclude={"category": {"tier": {"name"}}}, include={"name", "category"} + ) assert dict1.get("name") == "M16" assert "category" in dict1 assert dict1["category"]["name"] == "Weapons" @@ -159,7 +161,10 @@ def test_dumping_dict_without_primary_keys(sample_data): "email": "test@test.com", "first_name": "Anna", "password": "ijacids7^*&", - "roles": [{"name": "User", 'userrole': None}, {"name": "Admin", 'userrole': None}], + "roles": [ + {"name": "User", "userrole": None}, + {"name": "Admin", "userrole": None}, + ], }, "name": "M16", } @@ -170,7 +175,10 @@ def test_dumping_dict_without_primary_keys(sample_data): "email": "test@test.com", "first_name": "Anna", "password": "ijacids7^*&", - "roles": [{"name": "User", 'userrole': None}, {"name": "Admin", 'userrole': None}], + "roles": [ + {"name": "User", "userrole": None}, + {"name": "Admin", "userrole": None}, + ], }, "name": "Teddy Bear", } From cca0c8bd8c1eef4f643736ffe1f91a1022aa7720 Mon Sep 17 00:00:00 2001 From: collerek Date: Sat, 16 Dec 2023 18:48:18 +0100 Subject: [PATCH 15/95] WIP - working on proper populating __dict__ for relations for new schema dumping, some work on openapi docs, failing 13/442 --- ormar/models/descriptors/descriptors.py | 23 +++++++++- ormar/models/helpers/models.py | 2 +- ormar/models/helpers/relations.py | 44 ++++++++++++++++++- ormar/models/helpers/validation.py | 11 ++++- ormar/models/metaclass.py | 5 +-- ormar/models/newbasemodel.py | 40 +++++++++-------- ormar/relations/relation.py | 10 ++++- .../test_dumping_model_to_dict.py | 8 ++-- ...est_docs_with_multiple_relations_to_one.py | 2 +- tests/test_fastapi/test_excluding_fields.py | 9 ++-- tests/test_fastapi/test_fastapi_docs.py | 4 +- .../test_fastapi/test_skip_reverse_models.py | 14 +++++- 12 files changed, 131 insertions(+), 41 deletions(-) diff --git a/ormar/models/descriptors/descriptors.py b/ormar/models/descriptors/descriptors.py index dde90b4e2..9030b0bdd 100644 --- a/ormar/models/descriptors/descriptors.py +++ b/ormar/models/descriptors/descriptors.py @@ -1,5 +1,5 @@ import base64 -from typing import Any, TYPE_CHECKING, Type +from typing import Any, List, TYPE_CHECKING, Type from ormar.fields.parsers import encode_json @@ -110,15 +110,34 @@ def __set__(self, instance: "Model", value: Any) -> None: model = instance.ormar_config.model_fields[self.name].expand_relationship( value=value, child=instance ) + if isinstance(instance.__dict__.get(self.name), list): # virtual foreign key or many to many # TODO: Fix double items in dict, no effect on real action just ugly repr - instance.__dict__[self.name].append(model) + self._populate_models_dict_if_not_present(instance=instance, model=model) else: # foreign key relation instance.__dict__[self.name] = model instance.set_save_status(False) + def _populate_models_dict_if_not_present(self, instance: "Model", model: Any) -> None: + models = instance.__dict__[self.name] + if isinstance(model, list): + for model_ in model: + self._append_to_list_if_not_present(models=models, model=model_) + return + + self._append_to_list_if_not_present(models=models, model=model) + + @staticmethod + def _append_to_list_if_not_present(models: List["Model"], model: Any) -> None: + try: + if model not in models: + models.append(model) + except ReferenceError: + models.clear() + models.append(model) + class PropertyDescriptor: """ diff --git a/ormar/models/helpers/models.py b/ormar/models/helpers/models.py index cdc0404a6..05ec0dee0 100644 --- a/ormar/models/helpers/models.py +++ b/ormar/models/helpers/models.py @@ -47,7 +47,7 @@ def populate_default_options_values( # noqa: CCR001 :param model_fields: dict of model fields :type model_fields: Union[Dict[str, type], Dict] """ - new_model.ormar_config.model_fields = model_fields + new_model.ormar_config.model_fields.update(model_fields) if any(is_field_an_forward_ref(field) for field in model_fields.values()): new_model.ormar_config.requires_ref_update = True diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 2b0c9b746..1ff41dc0b 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -1,4 +1,8 @@ -from typing import TYPE_CHECKING, Type, cast +import inspect +from typing import List, TYPE_CHECKING, Type, Union, cast + +from pydantic import BaseModel, create_model +from pydantic.fields import FieldInfo import ormar from ormar import ForeignKey, ManyToMany @@ -133,9 +137,47 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: skip_field=model_field.skip_reverse, ) if not model_field.skip_reverse: + field_type = model_field.to.ormar_config.model_fields[related_name].__type__ + field_type = replace_models_with_copy(annotation=field_type) + if not model_field.is_multi: + field_type = Union[field_type, List[field_type], None] + model_field.to.model_fields[related_name] = FieldInfo.from_annotated_attribute( + annotation=field_type, default=None + ) + model_field.to.model_rebuild(force=True) setattr(model_field.to, related_name, RelationDescriptor(name=related_name)) +def replace_models_with_copy(annotation: Type) -> Type: + """ + Replaces all models in annotation with their copies to avoid circular references. + + :param annotation: annotation to replace models in + :type annotation: Type + :return: annotation with replaced models + :rtype: Type + """ + if inspect.isclass(annotation) and issubclass(annotation, BaseModel): + return create_copy_to_avoid_circular_references(model=annotation) + elif hasattr(annotation, "__origin__"): + if annotation.__origin__ == list: + return List[ + replace_models_with_copy(annotation=annotation.__args__[0]) + ] # type: ignore + elif annotation.__origin__ == Union: + args = annotation.__args__ + new_args = [replace_models_with_copy(annotation=arg) for arg in args] + return Union[tuple(new_args)] + else: + return annotation + else: + return annotation + + +def create_copy_to_avoid_circular_references(model: Type["Model"]) -> Type["BaseModel"]: + return cast(Type[BaseModel], type(model.__name__, (model,), {})) + + def register_through_shortcut_fields(model_field: "ManyToManyField") -> None: """ Registers m2m relation through shortcut on both ends of the relation. diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 58faad02d..bea703e46 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -1,6 +1,7 @@ import base64 import decimal import numbers +from types import NoneType from typing import ( Any, Callable, @@ -167,6 +168,14 @@ def get_pydantic_example_repr(type_: Any) -> Any: :return: representation to include in example :rtype: Any """ + if hasattr(type_, "__origin__"): + if type_.__origin__ == Union: + values = tuple(get_pydantic_example_repr(x) for x in type_.__args__ if x is not NoneType) + if len(values) == 1: + return values[0] + return values + if type_.__origin__ == list: + return [get_pydantic_example_repr(type_.__args__[0])] if issubclass(type_, (numbers.Number, decimal.Decimal)): return 0 if issubclass(type_, pydantic.BaseModel): @@ -266,4 +275,4 @@ def modify_schema_example(model: Type["Model"]) -> None: # noqa CCR001 :type model: Model class """ if not config_field_not_set(model=model, field_name="model_fields"): - model.model_config["schema_extra"] = construct_schema_function_without_choices() + model.model_config["json_schema_extra"] = construct_schema_function_without_choices() diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 27709acf7..cfa1d2a9b 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -18,8 +18,6 @@ import sqlalchemy from pydantic._internal._model_construction import complete_model_class from pydantic.fields import FieldInfo -from pydantic.plugin._schema_validator import create_schema_validator -from pydantic_core import SchemaSerializer from sqlalchemy.sql.schema import ColumnCollectionConstraint import ormar # noqa I100 @@ -624,8 +622,7 @@ def __new__( # type: ignore # noqa: CCR001 add_cached_properties(new_model) if hasattr(new_model, "ormar_config"): - if model_fields: - populate_default_options_values(new_model, model_fields) + populate_default_options_values(new_model, model_fields) check_required_meta_parameters(new_model) add_property_fields(new_model, attrs) register_signals(new_model=new_model) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index e1bbf5722..9159c493c 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -206,6 +206,8 @@ def __getattr__(self, item: str) -> Any: # TODO: Check __pydantic_extra__ if item == "__pydantic_extra__": return None + if item =="__pydantic_serializer__": + breakpoint() return super().__getattr__(item) def __getstate__(self) -> Dict[Any, Any]: @@ -633,13 +635,14 @@ def _extract_nested_models_from_list( exclude_primary_keys=exclude_primary_keys, exclude_through_models=exclude_through_models, ) - model.populate_through_models( - model=model, - model_dict=model_dict, - include=include, - exclude=exclude, - relation_map=relation_map, - ) + if not exclude_through_models: + model.populate_through_models( + model=model, + model_dict=model_dict, + include=include, + exclude=exclude, + relation_map=relation_map, + ) result.append(model_dict) except ReferenceError: # pragma no cover continue @@ -679,8 +682,8 @@ def populate_through_models( through_instance = getattr(model, through_model) if through_instance: model_dict[through_model] = through_instance.dict() - else: - model_dict[through_model] = None + # else: + # model_dict[through_model] = None @classmethod def _skip_ellipsis( @@ -775,15 +778,16 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 exclude_primary_keys=exclude_primary_keys, exclude_through_models=exclude_through_models, ) - nested_model.populate_through_models( - model=nested_model, - model_dict=model_dict, - include=self._convert_all(self._skip_ellipsis(include, field)), - exclude=self._convert_all(self._skip_ellipsis(exclude, field)), - relation_map=self._skip_ellipsis( - relation_map, field, default_return=dict() - ), - ) + if not exclude_through_models: + nested_model.populate_through_models( + model=nested_model, + model_dict=model_dict, + include=self._convert_all(self._skip_ellipsis(include, field)), + exclude=self._convert_all(self._skip_ellipsis(exclude, field)), + relation_map=self._skip_ellipsis( + relation_map, field, default_return=dict() + ), + ) dict_instance[field] = model_dict else: dict_instance[field] = None diff --git a/ormar/relations/relation.py b/ormar/relations/relation.py index d73d627fb..982ac31bd 100644 --- a/ormar/relations/relation.py +++ b/ormar/relations/relation.py @@ -162,9 +162,17 @@ def add(self, child: "Model") -> None: rel = rel or [] if not isinstance(rel, list): rel = [rel] - rel.append(child) + self._populate_owner_side_dict(rel=rel, child=child) self._owner.__dict__[relation_name] = rel + def _populate_owner_side_dict(self, rel:List["Model"], child: "Model") -> None: + try: + if child not in rel: + rel.append(child) + except ReferenceError: + rel.clear() + rel.append(child) + def remove(self, child: Union["NewBaseModel", Type["NewBaseModel"]]) -> None: """ Removes child Model from relation, either sets None as related model or removes diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index 65b1aa53c..e2e1dbde3 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -162,8 +162,8 @@ def test_dumping_dict_without_primary_keys(sample_data): "first_name": "Anna", "password": "ijacids7^*&", "roles": [ - {"name": "User", "userrole": None}, - {"name": "Admin", "userrole": None}, + {"name": "User"}, + {"name": "Admin"}, ], }, "name": "M16", @@ -176,8 +176,8 @@ def test_dumping_dict_without_primary_keys(sample_data): "first_name": "Anna", "password": "ijacids7^*&", "roles": [ - {"name": "User", "userrole": None}, - {"name": "Admin", "userrole": None}, + {"name": "User"}, + {"name": "Admin"}, ], }, "name": "Teddy Bear", diff --git a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py index ebe863aab..a409d83ce 100644 --- a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py +++ b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py @@ -69,4 +69,4 @@ async def test_all_endpoints(): components = schema["components"]["schemas"] assert all(x in components for x in ["CA", "CB1", "CB2"]) pk_onlys = [x for x in list(components.keys()) if x.startswith("PkOnly")] - assert len(pk_onlys) == 2 + assert len(pk_onlys) == 4 diff --git a/tests/test_fastapi/test_excluding_fields.py b/tests/test_fastapi/test_excluding_fields.py index 6a2fb5f1c..059ab225a 100644 --- a/tests/test_fastapi/test_excluding_fields.py +++ b/tests/test_fastapi/test_excluding_fields.py @@ -82,7 +82,8 @@ async def get_category(category_id: int): @app.get("/categories/nt/{category_id}") async def get_category_no_through(category_id: int): category = await Category.objects.select_related("items").get(pk=category_id) - return category.dict(exclude_through_models=True) + result = category.dict(exclude_through_models=True) + return result @app.get("/categories/ntp/{category_id}") @@ -122,9 +123,6 @@ async def test_all_endpoints(): no_pk_item = (await client.get(f"/items/{item_check.id}")).json() assert no_pk_item == item - no_pk_item2 = (await client.get(f"/items/fex/{item_check.id}")).json() - assert no_pk_item2 == item - no_pk_category = ( await client.get(f"/categories/{item_check.categories[0].id}") ).json() @@ -151,3 +149,6 @@ async def test_all_endpoints(): await client.get(f"/categories/ntp/{item_check.categories[0].id}") ).json() assert no_through_category == {"items": [{"name": "test"}], "name": "test cat"} + + no_pk_item2 = (await client.get(f"/items/fex/{item_check.id}")).json() + assert no_pk_item2 == item diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index 19e4cdea5..fe0662f79 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -131,7 +131,7 @@ async def test_all_endpoints(): def test_schema_modification(): - schema = Item.schema() + schema = Item.model_json_schema() assert any(x.get("type") == "array" for x in schema["properties"]["categories"]["anyOf"]) assert schema["properties"]["categories"]["title"] == "Categories" assert schema["example"] == { @@ -142,7 +142,7 @@ def test_schema_modification(): "test_P": [{"a": 0, "b": {"c": "string", "d": "string", "e": "string"}}], } - schema = Category.schema() + schema = Category.model_json_schema() assert schema["example"] == { "id": 0, "name": "string", diff --git a/tests/test_fastapi/test_skip_reverse_models.py b/tests/test_fastapi/test_skip_reverse_models.py index 576d16cc1..e119101b9 100644 --- a/tests/test_fastapi/test_skip_reverse_models.py +++ b/tests/test_fastapi/test_skip_reverse_models.py @@ -53,6 +53,10 @@ class Category(ormar.Model): name: str = ormar.String(max_length=40) +class Category2(Category): + model_config = dict(extra="forbid") + + class Post(ormar.Model): ormar_config = base_ormar_config.copy() @@ -76,6 +80,12 @@ async def create_category(category: Category): await category.save_related(follow=True, save_all=True) return category +@app.post("/categories/forbid/", response_model=Category2) +async def create_category(category: Category2): + await category.save() + await category.save_related(follow=True, save_all=True) + return category + @app.post("/posts/", response_model=Post) async def create_post(post: Post): @@ -148,6 +158,6 @@ async def test_queries(): wrong_category = {"name": "Test category3", "posts": [{"title": "Test Post"}]} # cannot add posts if skipped, will be error with extra forbid - Category.__config__.extra = "forbid" - response = await client.post("/categories/", json=wrong_category) + assert Category2.model_config["extra"] == "forbid" + response = await client.post("/categories/forbid/", json=wrong_category) assert response.status_code == 422 From 69660f72976e3b5c04d01be86df4c3a816abd29f Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 17 Dec 2023 16:52:45 +0100 Subject: [PATCH 16/95] WIP - remove property fields as pydantic has now computed_field on its own, failing 9/442 --- ormar/__init__.py | 1 - ormar/decorators/__init__.py | 3 -- ormar/decorators/property_field.py | 32 ------------------- ormar/models/metaclass.py | 7 ++-- ormar/models/newbasemodel.py | 2 +- ormar/models/quick_access_views.py | 1 + .../test_excluding_fields_in_fastapi.py | 5 +-- ...est_docs_with_multiple_relations_to_one.py | 5 +-- tests/test_fastapi/test_excluding_fields.py | 18 ----------- .../test_inheritance_concrete.py | 15 +++++---- .../test_inheritance_of_property_fields.py | 7 ++-- .../test_equality_and_hash.py | 1 - .../test_model_definition/test_properties.py | 19 +++++------ .../test_pydantic_only_fields.py | 8 ++--- 14 files changed, 36 insertions(+), 88 deletions(-) delete mode 100644 ormar/decorators/property_field.py diff --git a/ormar/__init__.py b/ormar/__init__.py index e4d3e1165..1d9b9c220 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -36,7 +36,6 @@ pre_relation_remove, pre_save, pre_update, - property_field, ) from ormar.exceptions import ( # noqa: I100 ModelDefinitionError, diff --git a/ormar/decorators/__init__.py b/ormar/decorators/__init__.py index c6f42d048..1d71d6cda 100644 --- a/ormar/decorators/__init__.py +++ b/ormar/decorators/__init__.py @@ -3,11 +3,9 @@ Currently only: -* property_field - exposing @property like function as field in Model.dict() * predefined signals decorators (pre/post + save/update/delete) """ -from ormar.decorators.property_field import property_field from ormar.decorators.signals import ( post_bulk_update, post_delete, @@ -23,7 +21,6 @@ ) __all__ = [ - "property_field", "post_bulk_update", "post_delete", "post_save", diff --git a/ormar/decorators/property_field.py b/ormar/decorators/property_field.py deleted file mode 100644 index 69ec9da52..000000000 --- a/ormar/decorators/property_field.py +++ /dev/null @@ -1,32 +0,0 @@ -import inspect -from collections.abc import Callable -from typing import Union - -from ormar.exceptions import ModelDefinitionError - - -def property_field(func: Callable) -> Union[property, Callable]: - """ - Decorator to set a property like function on Model to be exposed - as field in dict() and fastapi response. - Although you can decorate a @property field like this and this will work, - mypy validation will complain about this. - Note that "fields" exposed like this do not go through validation. - - :raises ModelDefinitionError: if method has any other argument than self. - :param func: decorated function to be exposed - :type func: Callable - :return: decorated function passed in func param, with set __property_field__ = True - :rtype: Union[property, Callable] - """ - if isinstance(func, property): # pragma: no cover - func.fget.__property_field__ = True - else: - arguments = list(inspect.signature(func).parameters.keys()) - if len(arguments) > 1 or arguments[0] != "self": - raise ModelDefinitionError( - "property_field decorator can be used " - "only on methods with no arguments" - ) - func.__dict__["__property_field__"] = True - return func diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index cfa1d2a9b..cb2582fb0 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -17,7 +17,7 @@ import pydantic import sqlalchemy from pydantic._internal._model_construction import complete_model_class -from pydantic.fields import FieldInfo +from pydantic.fields import ComputedFieldInfo, FieldInfo from sqlalchemy.sql.schema import ColumnCollectionConstraint import ormar # noqa I100 @@ -130,10 +130,7 @@ def add_property_fields(new_model: Type["Model"], attrs: Dict) -> None: # noqa: """ props = set() for var_name, value in attrs.items(): - if isinstance(value, property): - value = value.fget - field_config = getattr(value, "__property_field__", None) - if field_config: + if hasattr(value, "decorator_info") and isinstance(value.decorator_info, ComputedFieldInfo): props.add(var_name) if config_field_not_set(model=new_model, field_name="property_fields"): diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 9159c493c..51ea6ce6b 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -303,7 +303,7 @@ def _process_kwargs(self, kwargs: Dict) -> Tuple[Dict, Dict]: # noqa: CCR001 """ property_fields = self.ormar_config.property_fields model_fields = self.ormar_config.model_fields - pydantic_fields = set(self.__fields__.keys()) + pydantic_fields = set(self.model_fields.keys()) # remove property fields for prop_filed in property_fields: diff --git a/ormar/models/quick_access_views.py b/ormar/models/quick_access_views.py index 318c38e9d..464d9b1ec 100644 --- a/ormar/models/quick_access_views.py +++ b/ormar/models/quick_access_views.py @@ -5,6 +5,7 @@ quick_access_set = { "Config", "model_config", + "model_fields", "__cached_hash__", "__class__", "__config__", diff --git a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py index ce5ab0e45..eef49d4a5 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py @@ -9,9 +9,10 @@ from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient +from pydantic import computed_field import ormar -from ormar import post_save, property_field +from ormar import post_save from tests.settings import DATABASE_URL app = FastAPI() @@ -73,7 +74,7 @@ class RandomModel(ormar.Model): last_name: str = ormar.String(max_length=255) created_date: datetime.datetime = ormar.DateTime(server_default=sqlalchemy.func.now()) - @property_field + @computed_field def full_name(self) -> str: return " ".join([self.first_name, self.last_name]) diff --git a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py index a409d83ce..a4a8465ca 100644 --- a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py +++ b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py @@ -67,6 +67,7 @@ async def test_all_endpoints(): assert response.status_code == 200, response.text schema = response.json() components = schema["components"]["schemas"] - assert all(x in components for x in ["CA", "CB1", "CB2"]) - pk_onlys = [x for x in list(components.keys()) if x.startswith("PkOnly")] + raw_names_w_o_modules = [x.split("__")[-1] for x in components.keys()] + assert all(x in raw_names_w_o_modules for x in ["CA", "CB1", "CB2"]) + pk_onlys = [x for x in list(raw_names_w_o_modules) if x.startswith("PkOnly")] assert len(pk_onlys) == 4 diff --git a/tests/test_fastapi/test_excluding_fields.py b/tests/test_fastapi/test_excluding_fields.py index 059ab225a..62a6c228e 100644 --- a/tests/test_fastapi/test_excluding_fields.py +++ b/tests/test_fastapi/test_excluding_fields.py @@ -92,21 +92,6 @@ async def get_category_no_pk_through(category_id: int): return category.dict(exclude_through_models=True, exclude_primary_keys=True) -@app.get( - "/items/fex/{item_id}", - response_model=Item, - response_model_exclude={ - "id", - "categories__id", - "categories__itemcategory", - "categories__items", - }, -) -async def get_item_excl(item_id: int): - item = await Item.objects.select_all().get(pk=item_id) - return item - - @pytest.mark.asyncio async def test_all_endpoints(): client = AsyncClient(app=app, base_url="http://testserver") @@ -149,6 +134,3 @@ async def test_all_endpoints(): await client.get(f"/categories/ntp/{item_check.categories[0].id}") ).json() assert no_through_category == {"items": [{"name": "test"}], "name": "test cat"} - - no_pk_item2 = (await client.get(f"/items/fex/{item_check.id}")).json() - assert no_pk_item2 == item diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index 380d0424a..b53604e2f 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -7,11 +7,12 @@ import pydantic import pytest import sqlalchemy as sa +from pydantic import computed_field from sqlalchemy import create_engine import ormar import ormar.fields.constraints -from ormar import ModelDefinitionError, property_field +from ormar import ModelDefinitionError from ormar.exceptions import ModelError from ormar.models.metaclass import get_constraint_copy from tests.settings import DATABASE_URL @@ -29,8 +30,8 @@ class AuditModel(ormar.Model): created_by: str = ormar.String(max_length=100) updated_by: str = ormar.String(max_length=100, default="Sam") - @property_field - def audit(self): # pragma: no cover + @computed_field + def audit(self) -> str: # pragma: no cover return f"{self.created_by} {self.updated_by}" @@ -75,12 +76,12 @@ class Category(DateFieldsModel, AuditModel): name: str = ormar.String(max_length=50, unique=True, index=True) code: int = ormar.Integer() - @property_field - def code_name(self): + @computed_field + def code_name(self) -> str: return f"{self.code}:{self.name}" - @property_field - def audit(self): + @computed_field + def audit(self) -> str: return f"{self.created_by} {self.updated_by}" diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py index c0a98f448..e52673327 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py @@ -2,6 +2,7 @@ import pytest import sqlalchemy import sqlalchemy as sa +from pydantic import computed_field import ormar from tests.settings import DATABASE_URL @@ -16,7 +17,7 @@ class BaseFoo(ormar.Model): name: str = ormar.String(max_length=100) - @ormar.property_field + @computed_field def prefixed_name(self) -> str: return "prefix_" + self.name @@ -27,7 +28,7 @@ class Foo(BaseFoo): database = database, ) - @ormar.property_field + @computed_field def double_prefixed_name(self) -> str: return "prefix2_" + self.name @@ -40,7 +41,7 @@ class Bar(BaseFoo): database = database, ) - @ormar.property_field + @computed_field def prefixed_name(self) -> str: return "baz_" + self.name diff --git a/tests/test_model_definition/test_equality_and_hash.py b/tests/test_model_definition/test_equality_and_hash.py index 33a7607c8..e72082fe1 100644 --- a/tests/test_model_definition/test_equality_and_hash.py +++ b/tests/test_model_definition/test_equality_and_hash.py @@ -4,7 +4,6 @@ import sqlalchemy import ormar -from ormar import ModelDefinitionError, property_field from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_properties.py b/tests/test_model_definition/test_properties.py index 200e8904f..98a416fab 100644 --- a/tests/test_model_definition/test_properties.py +++ b/tests/test_model_definition/test_properties.py @@ -2,9 +2,10 @@ import databases import pytest import sqlalchemy +from pydantic import PydanticUserError, computed_field import ormar -from ormar import ModelDefinitionError, property_field +from ormar import ModelDefinitionError from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -22,16 +23,16 @@ class Song(ormar.Model): name: str = ormar.String(max_length=100) sort_order: int = ormar.Integer() - @property_field - def sorted_name(self): + @computed_field + def sorted_name(self) -> str: return f"{self.sort_order}: {self.name}" - @property_field - def sample(self): + @computed_field + def sample(self) -> str: return "sample" - @property_field - def sample2(self): + @computed_field + def sample2(self) -> str: return "sample2" @@ -72,9 +73,9 @@ async def test_sort_order_on_main_model(): def test_wrong_definition(): - with pytest.raises(ModelDefinitionError): + with pytest.raises(PydanticUserError): class WrongModel(ormar.Model): # pragma: no cover - @property_field + @computed_field def test(self, aa=10, bb=30): pass diff --git a/tests/test_model_definition/test_pydantic_only_fields.py b/tests/test_model_definition/test_pydantic_only_fields.py index e96f45c03..ffd0a64a8 100644 --- a/tests/test_model_definition/test_pydantic_only_fields.py +++ b/tests/test_model_definition/test_pydantic_only_fields.py @@ -3,9 +3,9 @@ import databases import pytest import sqlalchemy +from pydantic import computed_field import ormar -from ormar import property_field from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -23,11 +23,11 @@ class Album(ormar.Model): name: str = ormar.String(max_length=100) timestamp: datetime.datetime = ormar.DateTime(pydantic_only=True) - @property_field + @computed_field def name10(self) -> str: return self.name + "_10" - @property_field + @computed_field def name20(self) -> str: return self.name + "_20" @@ -35,7 +35,7 @@ def name20(self) -> str: def name30(self) -> str: return self.name + "_30" - @property_field + @computed_field def name40(self) -> str: return self.name + "_40" From b91bd49949f13e976d001c76816d54fd74d34cc3 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 17 Dec 2023 21:04:13 +0100 Subject: [PATCH 17/95] WIP - fixes in docs, failing 8/442 --- ormar/fields/many_to_many.py | 1 - ormar/models/helpers/relations.py | 24 +++++++++++++++--------- ormar/models/metaclass.py | 20 ++++++++++++++++++-- ormar/models/newbasemodel.py | 2 -- tests/test_fastapi/test_binary_fields.py | 14 ++++++++++---- tests/test_fastapi/test_fastapi_docs.py | 5 ++++- 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 73cc4f1d5..7e43c0eeb 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -12,7 +12,6 @@ overload, ) -from pydantic.v1.typing import evaluate_forwardref import ormar # noqa: I100 from ormar import ModelDefinitionError diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 1ff41dc0b..1f2d71da0 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -1,5 +1,5 @@ import inspect -from typing import List, TYPE_CHECKING, Type, Union, cast +from typing import List, TYPE_CHECKING, Optional, Type, Union, cast from pydantic import BaseModel, create_model from pydantic.fields import FieldInfo @@ -138,7 +138,7 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: ) if not model_field.skip_reverse: field_type = model_field.to.ormar_config.model_fields[related_name].__type__ - field_type = replace_models_with_copy(annotation=field_type) + field_type = replace_models_with_copy(annotation=field_type, source_model_field=model_field.name) if not model_field.is_multi: field_type = Union[field_type, List[field_type], None] model_field.to.model_fields[related_name] = FieldInfo.from_annotated_attribute( @@ -148,7 +148,7 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: setattr(model_field.to, related_name, RelationDescriptor(name=related_name)) -def replace_models_with_copy(annotation: Type) -> Type: +def replace_models_with_copy(annotation: Type, source_model_field: Optional[str] = None) -> Type: """ Replaces all models in annotation with their copies to avoid circular references. @@ -157,16 +157,16 @@ def replace_models_with_copy(annotation: Type) -> Type: :return: annotation with replaced models :rtype: Type """ - if inspect.isclass(annotation) and issubclass(annotation, BaseModel): - return create_copy_to_avoid_circular_references(model=annotation) + if inspect.isclass(annotation) and issubclass(annotation, ormar.Model): + return create_copy_to_avoid_circular_references(model=annotation, source_model_field=source_model_field) elif hasattr(annotation, "__origin__"): if annotation.__origin__ == list: return List[ - replace_models_with_copy(annotation=annotation.__args__[0]) + replace_models_with_copy(annotation=annotation.__args__[0], source_model_field=source_model_field) ] # type: ignore elif annotation.__origin__ == Union: args = annotation.__args__ - new_args = [replace_models_with_copy(annotation=arg) for arg in args] + new_args = [replace_models_with_copy(annotation=arg, source_model_field=source_model_field) for arg in args] return Union[tuple(new_args)] else: return annotation @@ -174,8 +174,14 @@ def replace_models_with_copy(annotation: Type) -> Type: return annotation -def create_copy_to_avoid_circular_references(model: Type["Model"]) -> Type["BaseModel"]: - return cast(Type[BaseModel], type(model.__name__, (model,), {})) +def create_copy_to_avoid_circular_references(model: Type["Model"], source_model_field: Optional[str] = None) -> Type["BaseModel"]: + new_model = create_model( + model.__name__, + __base__=model, + **{k: (v.annotation, v.default) for k, v in model.model_fields.items() if k != source_model_field}, + ) + new_model.model_fields.pop(source_model_field, None) + return new_model def register_through_shortcut_fields(model_field: "ManyToManyField") -> None: diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index cb2582fb0..8944d03e9 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -16,6 +16,7 @@ import databases import pydantic import sqlalchemy +from pydantic._internal._generics import PydanticGenericMetadata from pydantic._internal._model_construction import complete_model_class from pydantic.fields import ComputedFieldInfo, FieldInfo from sqlalchemy.sql.schema import ColumnCollectionConstraint @@ -569,7 +570,14 @@ def add_field_descriptor( class ModelMetaclass(pydantic._internal._model_construction.ModelMetaclass): def __new__( # type: ignore # noqa: CCR001 - mcs: "ModelMetaclass", name: str, bases: Any, attrs: dict + mcs: "ModelMetaclass", + name: str, + bases: Any, + attrs: dict, + __pydantic_generic_metadata__: PydanticGenericMetadata | None = None, + __pydantic_reset_parent_namespace__: bool = True, + _create_model_module: str | None = None, + **kwargs ) -> "ModelMetaclass": """ Metaclass used by ormar Models that performs configuration @@ -614,7 +622,15 @@ def __new__( # type: ignore # noqa: CCR001 if "ormar_config" in attrs: attrs["model_config"]["ignored_types"] = (OrmarConfig,) attrs["model_config"]["from_attributes"] = True - new_model = super().__new__(mcs, name, bases, attrs) # type: ignore + new_model = super().__new__( + mcs, # type: ignore + name, + bases, + attrs, + __pydantic_generic_metadata__=__pydantic_generic_metadata__, + __pydantic_reset_parent_namespace__=__pydantic_reset_parent_namespace__, + _create_model_module=_create_model_module, + **kwargs) add_cached_properties(new_model) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 51ea6ce6b..9989a9b09 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -206,8 +206,6 @@ def __getattr__(self, item: str) -> Any: # TODO: Check __pydantic_extra__ if item == "__pydantic_extra__": return None - if item =="__pydantic_serializer__": - breakpoint() return super().__getattr__(item) def __getstate__(self) -> Dict[Any, Any]: diff --git a/tests/test_fastapi/test_binary_fields.py b/tests/test_fastapi/test_binary_fields.py index 5dce624e5..cd06831c9 100644 --- a/tests/test_fastapi/test_binary_fields.py +++ b/tests/test_fastapi/test_binary_fields.py @@ -1,6 +1,7 @@ import base64 import json import uuid +from enum import Enum from typing import List import databases @@ -47,15 +48,20 @@ async def shutdown() -> None: database=database, ) + +class BinaryEnum(Enum): + blob3 = blob3 + blob4 = blob4 + blob5 = blob5 + blob6 = blob6 + + class BinaryThing(ormar.Model): ormar_config = base_ormar_config.copy(tablename = "things") id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.Text(default="") - bt: str = ormar.LargeBinary( - max_length=1000, - choices=[blob3, blob4, blob5, blob6], - represent_as_base64_str=True, + bt: str = ormar.Enum(enum_class=BinaryEnum, represent_as_base64_str=True, ) diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index fe0662f79..085da98ad 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -5,6 +5,7 @@ import pydantic import pytest import sqlalchemy +import uvicorn from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient @@ -160,4 +161,6 @@ def test_schema_modification(): def test_schema_gen(): schema = app.openapi() assert "Category" in schema["components"]["schemas"] - assert "Item" in schema["components"]["schemas"] + subschemas = [x.split("__")[-1] for x in schema["components"]["schemas"]] + assert "Item-Input" in subschemas + assert "Item-Output" in subschemas From 8c688b89690b6aab6140f78051d1c197fb675e10 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 19 Dec 2023 15:23:10 +0100 Subject: [PATCH 18/95] WIP - fix tests for largebinary schema, wrapped bytes fields fail in pydantic, will be fixed in pydantic-core, remaining is circural schema for related models, failing 6/442 --- ormar/models/helpers/pydantic.py | 2 +- tests/test_fastapi/test_binary_fields.py | 10 ++-------- tests/test_fastapi/test_fastapi_usage.py | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index 23372434c..b7d78a338 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -110,7 +110,7 @@ def get_pydantic_base_orm_config() -> pydantic.ConfigDict: :rtype: pydantic Config """ - return ConfigDict(validate_assignment=True) + return ConfigDict(validate_assignment=True, ser_json_bytes="base64") def get_potential_fields(attrs: Union[Dict, MappingProxyType]) -> Dict: diff --git a/tests/test_fastapi/test_binary_fields.py b/tests/test_fastapi/test_binary_fields.py index cd06831c9..0564216de 100644 --- a/tests/test_fastapi/test_binary_fields.py +++ b/tests/test_fastapi/test_binary_fields.py @@ -61,8 +61,7 @@ class BinaryThing(ormar.Model): id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.Text(default="") - bt: str = ormar.Enum(enum_class=BinaryEnum, represent_as_base64_str=True, - ) + bt: str = ormar.LargeBinary(represent_as_base64_str=True, max_length=100) @app.get("/things", response_model=List[BinaryThing]) @@ -101,11 +100,6 @@ async def test_read_main(): def test_schema(): - schema = BinaryThing.schema() + schema = BinaryThing.model_json_schema() assert schema["properties"]["bt"]["format"] == "base64" - converted_choices = ["7g==", "/w==", "8CiMKA==", "wyg="] - assert len(schema["properties"]["bt"]["enum"]) == 4 - assert all( - choice in schema["properties"]["bt"]["enum"] for choice in converted_choices - ) assert schema["example"]["bt"] == "string" diff --git a/tests/test_fastapi/test_fastapi_usage.py b/tests/test_fastapi/test_fastapi_usage.py index 29a2ad9fe..7d7ad8466 100644 --- a/tests/test_fastapi/test_fastapi_usage.py +++ b/tests/test_fastapi/test_fastapi_usage.py @@ -55,7 +55,6 @@ async def test_read_main(): assert response.json() == { "category": { "id": None, - "items": [{"id": 1, "name": "test"}], "name": "test cat", }, "id": 1, @@ -63,3 +62,4 @@ async def test_read_main(): } item = Item(**response.json()) assert item.id == 1 + assert item.category.items[0].id == 1 From 5cb310ae294e5a3c309ee55939bc8a2ef4d46338 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 17 Jan 2024 12:56:27 +0100 Subject: [PATCH 19/95] WIP - fix to pk only models in schemas --- ormar/fields/base.py | 1 + ormar/fields/foreign_key.py | 32 +- ormar/fields/many_to_many.py | 28 +- ormar/models/helpers/relations.py | 41 +- ormar/models/newbasemodel.py | 31 +- poetry.lock | 729 +++++++++--------- pyproject.toml | 2 +- .../test_excludes_with_get_pydantic.py | 2 +- .../test_relations_with_nested_defaults.py | 10 +- 9 files changed, 466 insertions(+), 410 deletions(-) diff --git a/ormar/fields/base.py b/ormar/fields/base.py index 40c47f1dd..dd4602516 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -76,6 +76,7 @@ def __init__(self, **kwargs: Any) -> None: self.owner: Type["Model"] = kwargs.pop("owner", None) self.to: Type["Model"] = kwargs.pop("to", None) + self.to_pk_only: Type["Model"] = kwargs.pop("to_pk_only", None) self.through: Type["Model"] = kwargs.pop("through", None) self.self_reference: bool = kwargs.pop("self_reference", False) self.self_reference_primary: Optional[str] = kwargs.pop( diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index c58518f35..48e6564db 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -88,7 +88,7 @@ def create_dummy_model( def populate_fk_params_based_on_to_model( to: Type["T"], nullable: bool, onupdate: str = None, ondelete: str = None -) -> Tuple[Any, List, Any]: +) -> Tuple[Any, List, Any, Any]: """ Based on target to model to which relation leads to populates the type of the pydantic field to use, ForeignKey constraint and type of the target column field. @@ -122,7 +122,7 @@ def populate_fk_params_based_on_to_model( ) ] column_type = to_field.column_type - return __type__, constraints, column_type + return __type__, constraints, column_type, pk_only_model def validate_not_allowed_fields(kwargs: Dict) -> None: @@ -259,13 +259,18 @@ def ForeignKey( # type: ignore # noqa CFQ002 sql_nullable = nullable if sql_nullable is None else sql_nullable validate_not_allowed_fields(kwargs) - + pk_only_model = None if to.__class__ == ForwardRef: __type__ = to if not nullable else Optional[to] constraints: List = [] column_type = None else: - __type__, constraints, column_type = populate_fk_params_based_on_to_model( + ( + __type__, + constraints, + column_type, + pk_only_model, + ) = populate_fk_params_based_on_to_model( to=to, # type: ignore nullable=nullable, ondelete=ondelete, @@ -275,6 +280,7 @@ def ForeignKey( # type: ignore # noqa CFQ002 namespace = dict( __type__=__type__, to=to, + to_pk_only=pk_only_model, through=None, alias=name, name=kwargs.pop("real_name", None), @@ -372,6 +378,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: self.__type__, self.constraints, self.column_type, + self.to_pk_only, ) = populate_fk_params_based_on_to_model( to=self.to, nullable=self.nullable, @@ -445,15 +452,17 @@ def _construct_model_from_dict( :return: (if needed) registered Model :rtype: Model """ + pk_only_model = None if ( len(value.keys()) == 1 and list(value.keys())[0] == self.to.ormar_config.pkname ): value["__pk_only__"] = True + pk_only_model = self.to_pk_only(**value) model = self.to(**value) if to_register: self.register_relation(model=model, child=child) - return model + return pk_only_model if pk_only_model is not None else model def _construct_model_from_pk( self, value: Any, child: "Model", to_register: bool @@ -476,11 +485,14 @@ def _construct_model_from_pk( if self.to.pk_type() == uuid.UUID and isinstance(value, str): # pragma: nocover value = uuid.UUID(value) if not isinstance(value, self.to.pk_type()): - raise RelationshipInstanceError( - f"Relationship error - ForeignKey {self.to.__name__} " - f"is of type {self.to.pk_type()} " - f"while {type(value)} passed as a parameter." - ) + if isinstance(value, self.to_pk_only): + value = getattr(value, self.to.ormar_config.pkname) + else: + raise RelationshipInstanceError( + f"Relationship error - ForeignKey {self.to.__name__} " + f"is of type {self.to.pk_type()} " + f"while {type(value)} passed as a parameter." + ) model = create_dummy_instance(fk=self.to, pk=value) if to_register: self.register_relation(model=model, child=child) diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 7e43c0eeb..9b904923c 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -16,7 +16,11 @@ import ormar # noqa: I100 from ormar import ModelDefinitionError from ormar.fields import BaseField -from ormar.fields.foreign_key import ForeignKeyField, validate_not_allowed_fields +from ormar.fields.foreign_key import ( + ForeignKeyField, + validate_not_allowed_fields, + create_dummy_model, +) if TYPE_CHECKING: # pragma no cover from ormar.models import Model, T @@ -47,7 +51,7 @@ def forbid_through_relations(through: Type["Model"]) -> None: def populate_m2m_params_based_on_to_model( to: Type["Model"], nullable: bool -) -> Tuple[Any, Any]: +) -> Tuple[Any, Any, Any]: """ Based on target to model to which relation leads to populates the type of the pydantic field to use and type of the target column field. @@ -60,13 +64,15 @@ def populate_m2m_params_based_on_to_model( :rtype: tuple with target pydantic type and target col type """ to_field = to.ormar_config.model_fields[to.ormar_config.pkname] + pk_only_model = create_dummy_model(to, to_field) + base_type = Union[to_field.__type__, to, pk_only_model, List[to], List[pk_only_model]] # type: ignore __type__ = ( - Union[to_field.__type__, to, List[to]] # type: ignore + base_type # type: ignore if not nullable - else Optional[Union[to_field.__type__, to, List[to]]] # type: ignore + else Optional[base_type] # type: ignore ) column_type = to_field.column_type - return __type__, column_type + return __type__, column_type, pk_only_model @overload @@ -130,7 +136,7 @@ def ManyToMany( # type: ignore forbid_through_relations(cast(Type["Model"], through)) validate_not_allowed_fields(kwargs) - + pk_only_model = None if to.__class__ == ForwardRef: __type__ = ( Union[to, List[to]] # type: ignore @@ -139,12 +145,13 @@ def ManyToMany( # type: ignore ) column_type = None else: - __type__, column_type = populate_m2m_params_based_on_to_model( + __type__, column_type, pk_only_model = populate_m2m_params_based_on_to_model( to=to, nullable=nullable # type: ignore ) namespace = dict( __type__=__type__, to=to, + to_pk_only=pk_only_model, through=through, alias=name, name=name, @@ -225,9 +232,14 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: if self.to.__class__ == ForwardRef: self.to = self.to._evaluate(globalns, localns, set()) - (self.__type__, self.column_type) = populate_m2m_params_based_on_to_model( + ( + self.__type__, + self.column_type, + pk_only_model, + ) = populate_m2m_params_based_on_to_model( to=self.to, nullable=self.nullable ) + self.to_pk_only = pk_only_model if self.through.__class__ == ForwardRef: self.through = self.through._evaluate(globalns, localns, set()) diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 1f2d71da0..44d9997bf 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -1,5 +1,6 @@ +import copy import inspect -from typing import List, TYPE_CHECKING, Optional, Type, Union, cast +from typing import List, TYPE_CHECKING, Optional, Type, Union, cast, Dict from pydantic import BaseModel, create_model from pydantic.fields import FieldInfo @@ -138,17 +139,21 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: ) if not model_field.skip_reverse: field_type = model_field.to.ormar_config.model_fields[related_name].__type__ - field_type = replace_models_with_copy(annotation=field_type, source_model_field=model_field.name) + field_type = replace_models_with_copy( + annotation=field_type, source_model_field=model_field.name + ) if not model_field.is_multi: field_type = Union[field_type, List[field_type], None] model_field.to.model_fields[related_name] = FieldInfo.from_annotated_attribute( - annotation=field_type, default=None + annotation=field_type, default=None ) model_field.to.model_rebuild(force=True) setattr(model_field.to, related_name, RelationDescriptor(name=related_name)) -def replace_models_with_copy(annotation: Type, source_model_field: Optional[str] = None) -> Type: +def replace_models_with_copy( + annotation: Type, source_model_field: Optional[str] = None +) -> Type: """ Replaces all models in annotation with their copies to avoid circular references. @@ -158,15 +163,25 @@ def replace_models_with_copy(annotation: Type, source_model_field: Optional[str] :rtype: Type """ if inspect.isclass(annotation) and issubclass(annotation, ormar.Model): - return create_copy_to_avoid_circular_references(model=annotation, source_model_field=source_model_field) + return create_copy_to_avoid_circular_references( + model=annotation, source_model_field=source_model_field + ) elif hasattr(annotation, "__origin__"): if annotation.__origin__ == list: return List[ - replace_models_with_copy(annotation=annotation.__args__[0], source_model_field=source_model_field) + replace_models_with_copy( + annotation=annotation.__args__[0], + source_model_field=source_model_field, + ) ] # type: ignore elif annotation.__origin__ == Union: args = annotation.__args__ - new_args = [replace_models_with_copy(annotation=arg, source_model_field=source_model_field) for arg in args] + new_args = [ + replace_models_with_copy( + annotation=arg, source_model_field=source_model_field + ) + for arg in args + ] return Union[tuple(new_args)] else: return annotation @@ -174,13 +189,19 @@ def replace_models_with_copy(annotation: Type, source_model_field: Optional[str] return annotation -def create_copy_to_avoid_circular_references(model: Type["Model"], source_model_field: Optional[str] = None) -> Type["BaseModel"]: +def create_copy_to_avoid_circular_references( + model: Type["Model"], source_model_field: Optional[str] = None +) -> Type["BaseModel"]: + # original_field = model.model_fields.pop(source_model_field, None) + # original_annotation = model.__dict__.get("__annotations__", {}).pop(source_model_field, None) + # original_ormar_field = model.ormar_config.model_fields.pop(source_model_field, None) new_model = create_model( model.__name__, __base__=model, - **{k: (v.annotation, v.default) for k, v in model.model_fields.items() if k != source_model_field}, ) - new_model.model_fields.pop(source_model_field, None) + # model.model_fields[source_model_field] = original_field + # model.__dict__.get("__annotations__", {})[source_model_field] = original_annotation + # model.ormar_config.model_fields[source_model_field] = original_ormar_field return new_model diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 9989a9b09..b0317a868 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -73,7 +73,7 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass "__pk_only__", "__cached_hash__", "__pydantic_extra__", - "__pydantic_fields_set__" + "__pydantic_fields_set__", ) if TYPE_CHECKING: # pragma no cover @@ -208,6 +208,11 @@ def __getattr__(self, item: str) -> Any: return None return super().__getattr__(item) + def __getattribute__(self, item: str) -> Any: + if item == "__dict__": + print(item, sys._getframe(1)) + return super().__getattribute__(item) + def __getstate__(self) -> Dict[Any, Any]: state = super().__getstate__() self_dict = self.dict() @@ -627,12 +632,12 @@ def _extract_nested_models_from_list( for model in models: try: model_dict = model.dict( - relation_map=relation_map, - include=include, - exclude=exclude, - exclude_primary_keys=exclude_primary_keys, - exclude_through_models=exclude_through_models, - ) + relation_map=relation_map, + include=include, + exclude=exclude, + exclude_primary_keys=exclude_primary_keys, + exclude_through_models=exclude_through_models, + ) if not exclude_through_models: model.populate_through_models( model=model, @@ -669,9 +674,7 @@ def populate_through_models( if exclude and isinstance(exclude, Set): exclude = translate_list_to_dict(exclude) models_to_populate = model._get_not_excluded_fields( - fields=model.extract_through_names(), - include=include, - exclude=exclude + fields=model.extract_through_names(), include=include, exclude=exclude ) for through_model in models_to_populate: through_field = model.ormar_config.model_fields[through_model] @@ -780,8 +783,12 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 nested_model.populate_through_models( model=nested_model, model_dict=model_dict, - include=self._convert_all(self._skip_ellipsis(include, field)), - exclude=self._convert_all(self._skip_ellipsis(exclude, field)), + include=self._convert_all( + self._skip_ellipsis(include, field) + ), + exclude=self._convert_all( + self._skip_ellipsis(exclude, field) + ), relation_map=self._skip_ellipsis( relation_map, field, default_return=dict() ), diff --git a/poetry.lock b/poetry.lock index 726a15951..748f69fb0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -71,25 +71,26 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} [[package]] name = "anyio" -version = "3.7.1" +version = "4.2.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, - {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, ] [package.dependencies] -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] -doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] -test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (<0.22)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] [[package]] name = "asgi-lifespan" @@ -226,34 +227,34 @@ yaml = ["PyYAML"] [[package]] name = "black" -version = "23.12.0" +version = "23.12.1" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "black-23.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67f19562d367468ab59bd6c36a72b2c84bc2f16b59788690e02bbcb140a77175"}, - {file = "black-23.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbd75d9f28a7283b7426160ca21c5bd640ca7cd8ef6630b4754b6df9e2da8462"}, - {file = "black-23.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:593596f699ca2dcbbbdfa59fcda7d8ad6604370c10228223cd6cf6ce1ce7ed7e"}, - {file = "black-23.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:12d5f10cce8dc27202e9a252acd1c9a426c83f95496c959406c96b785a92bb7d"}, - {file = "black-23.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e73c5e3d37e5a3513d16b33305713237a234396ae56769b839d7c40759b8a41c"}, - {file = "black-23.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba09cae1657c4f8a8c9ff6cfd4a6baaf915bb4ef7d03acffe6a2f6585fa1bd01"}, - {file = "black-23.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace64c1a349c162d6da3cef91e3b0e78c4fc596ffde9413efa0525456148873d"}, - {file = "black-23.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:72db37a2266b16d256b3ea88b9affcdd5c41a74db551ec3dd4609a59c17d25bf"}, - {file = "black-23.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fdf6f23c83078a6c8da2442f4d4eeb19c28ac2a6416da7671b72f0295c4a697b"}, - {file = "black-23.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39dda060b9b395a6b7bf9c5db28ac87b3c3f48d4fdff470fa8a94ab8271da47e"}, - {file = "black-23.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7231670266ca5191a76cb838185d9be59cfa4f5dd401b7c1c70b993c58f6b1b5"}, - {file = "black-23.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:193946e634e80bfb3aec41830f5d7431f8dd5b20d11d89be14b84a97c6b8bc75"}, - {file = "black-23.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcf91b01ddd91a2fed9a8006d7baa94ccefe7e518556470cf40213bd3d44bbbc"}, - {file = "black-23.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:996650a89fe5892714ea4ea87bc45e41a59a1e01675c42c433a35b490e5aa3f0"}, - {file = "black-23.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdbff34c487239a63d86db0c9385b27cdd68b1bfa4e706aa74bb94a435403672"}, - {file = "black-23.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:97af22278043a6a1272daca10a6f4d36c04dfa77e61cbaaf4482e08f3640e9f0"}, - {file = "black-23.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ead25c273adfad1095a8ad32afdb8304933efba56e3c1d31b0fee4143a1e424a"}, - {file = "black-23.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c71048345bdbced456cddf1622832276d98a710196b842407840ae8055ade6ee"}, - {file = "black-23.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a832b6e00eef2c13b3239d514ea3b7d5cc3eaa03d0474eedcbbda59441ba5d"}, - {file = "black-23.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:6a82a711d13e61840fb11a6dfecc7287f2424f1ca34765e70c909a35ffa7fb95"}, - {file = "black-23.12.0-py3-none-any.whl", hash = "sha256:a7c07db8200b5315dc07e331dda4d889a56f6bf4db6a9c2a526fa3166a81614f"}, - {file = "black-23.12.0.tar.gz", hash = "sha256:330a327b422aca0634ecd115985c1c7fd7bdb5b5a2ef8aa9888a82e2ebe9437a"}, + {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, + {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, + {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, + {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, + {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, + {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, + {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, + {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, + {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, + {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, + {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, + {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, + {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, + {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, + {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, + {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, + {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, + {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, + {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, + {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, + {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, + {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, ] [package.dependencies] @@ -519,64 +520,64 @@ files = [ [[package]] name = "coverage" -version = "7.3.3" +version = "7.3.4" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d874434e0cb7b90f7af2b6e3309b0733cde8ec1476eb47db148ed7deeb2a9494"}, - {file = "coverage-7.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee6621dccce8af666b8c4651f9f43467bfbf409607c604b840b78f4ff3619aeb"}, - {file = "coverage-7.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1367aa411afb4431ab58fd7ee102adb2665894d047c490649e86219327183134"}, - {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f0f8f0c497eb9c9f18f21de0750c8d8b4b9c7000b43996a094290b59d0e7523"}, - {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db0338c4b0951d93d547e0ff8d8ea340fecf5885f5b00b23be5aa99549e14cfd"}, - {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d31650d313bd90d027f4be7663dfa2241079edd780b56ac416b56eebe0a21aab"}, - {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9437a4074b43c177c92c96d051957592afd85ba00d3e92002c8ef45ee75df438"}, - {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9e17d9cb06c13b4f2ef570355fa45797d10f19ca71395910b249e3f77942a837"}, - {file = "coverage-7.3.3-cp310-cp310-win32.whl", hash = "sha256:eee5e741b43ea1b49d98ab6e40f7e299e97715af2488d1c77a90de4a663a86e2"}, - {file = "coverage-7.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:593efa42160c15c59ee9b66c5f27a453ed3968718e6e58431cdfb2d50d5ad284"}, - {file = "coverage-7.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c944cf1775235c0857829c275c777a2c3e33032e544bcef614036f337ac37bb"}, - {file = "coverage-7.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eda7f6e92358ac9e1717ce1f0377ed2b9320cea070906ece4e5c11d172a45a39"}, - {file = "coverage-7.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c854c1d2c7d3e47f7120b560d1a30c1ca221e207439608d27bc4d08fd4aeae8"}, - {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:222b038f08a7ebed1e4e78ccf3c09a1ca4ac3da16de983e66520973443b546bc"}, - {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff4800783d85bff132f2cc7d007426ec698cdce08c3062c8d501ad3f4ea3d16c"}, - {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fc200cec654311ca2c3f5ab3ce2220521b3d4732f68e1b1e79bef8fcfc1f2b97"}, - {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:307aecb65bb77cbfebf2eb6e12009e9034d050c6c69d8a5f3f737b329f4f15fb"}, - {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ffb0eacbadb705c0a6969b0adf468f126b064f3362411df95f6d4f31c40d31c1"}, - {file = "coverage-7.3.3-cp311-cp311-win32.whl", hash = "sha256:79c32f875fd7c0ed8d642b221cf81feba98183d2ff14d1f37a1bbce6b0347d9f"}, - {file = "coverage-7.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:243576944f7c1a1205e5cd658533a50eba662c74f9be4c050d51c69bd4532936"}, - {file = "coverage-7.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a2ac4245f18057dfec3b0074c4eb366953bca6787f1ec397c004c78176a23d56"}, - {file = "coverage-7.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f9191be7af41f0b54324ded600e8ddbcabea23e1e8ba419d9a53b241dece821d"}, - {file = "coverage-7.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c0b1b8b5a4aebf8fcd227237fc4263aa7fa0ddcd4d288d42f50eff18b0bac4"}, - {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee453085279df1bac0996bc97004771a4a052b1f1e23f6101213e3796ff3cb85"}, - {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1191270b06ecd68b1d00897b2daddb98e1719f63750969614ceb3438228c088e"}, - {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:007a7e49831cfe387473e92e9ff07377f6121120669ddc39674e7244350a6a29"}, - {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:af75cf83c2d57717a8493ed2246d34b1f3398cb8a92b10fd7a1858cad8e78f59"}, - {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:811ca7373da32f1ccee2927dc27dc523462fd30674a80102f86c6753d6681bc6"}, - {file = "coverage-7.3.3-cp312-cp312-win32.whl", hash = "sha256:733537a182b5d62184f2a72796eb6901299898231a8e4f84c858c68684b25a70"}, - {file = "coverage-7.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:e995efb191f04b01ced307dbd7407ebf6e6dc209b528d75583277b10fd1800ee"}, - {file = "coverage-7.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbd8a5fe6c893de21a3c6835071ec116d79334fbdf641743332e442a3466f7ea"}, - {file = "coverage-7.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:50c472c1916540f8b2deef10cdc736cd2b3d1464d3945e4da0333862270dcb15"}, - {file = "coverage-7.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e9223a18f51d00d3ce239c39fc41410489ec7a248a84fab443fbb39c943616c"}, - {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f501e36ac428c1b334c41e196ff6bd550c0353c7314716e80055b1f0a32ba394"}, - {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:475de8213ed95a6b6283056d180b2442eee38d5948d735cd3d3b52b86dd65b92"}, - {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:afdcc10c01d0db217fc0a64f58c7edd635b8f27787fea0a3054b856a6dff8717"}, - {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fff0b2f249ac642fd735f009b8363c2b46cf406d3caec00e4deeb79b5ff39b40"}, - {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a1f76cfc122c9e0f62dbe0460ec9cc7696fc9a0293931a33b8870f78cf83a327"}, - {file = "coverage-7.3.3-cp38-cp38-win32.whl", hash = "sha256:757453848c18d7ab5d5b5f1827293d580f156f1c2c8cef45bfc21f37d8681069"}, - {file = "coverage-7.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad2453b852a1316c8a103c9c970db8fbc262f4f6b930aa6c606df9b2766eee06"}, - {file = "coverage-7.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b15e03b8ee6a908db48eccf4e4e42397f146ab1e91c6324da44197a45cb9132"}, - {file = "coverage-7.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:89400aa1752e09f666cc48708eaa171eef0ebe3d5f74044b614729231763ae69"}, - {file = "coverage-7.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c59a3e59fb95e6d72e71dc915e6d7fa568863fad0a80b33bc7b82d6e9f844973"}, - {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ede881c7618f9cf93e2df0421ee127afdfd267d1b5d0c59bcea771cf160ea4a"}, - {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3bfd2c2f0e5384276e12b14882bf2c7621f97c35320c3e7132c156ce18436a1"}, - {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7f3bad1a9313401ff2964e411ab7d57fb700a2d5478b727e13f156c8f89774a0"}, - {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:65d716b736f16e250435473c5ca01285d73c29f20097decdbb12571d5dfb2c94"}, - {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a702e66483b1fe602717020a0e90506e759c84a71dbc1616dd55d29d86a9b91f"}, - {file = "coverage-7.3.3-cp39-cp39-win32.whl", hash = "sha256:7fbf3f5756e7955174a31fb579307d69ffca91ad163467ed123858ce0f3fd4aa"}, - {file = "coverage-7.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cad9afc1644b979211989ec3ff7d82110b2ed52995c2f7263e7841c846a75348"}, - {file = "coverage-7.3.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:d299d379b676812e142fb57662a8d0d810b859421412b4d7af996154c00c31bb"}, - {file = "coverage-7.3.3.tar.gz", hash = "sha256:df04c64e58df96b4427db8d0559e95e2df3138c9916c96f9f6a4dd220db2fdb7"}, + {file = "coverage-7.3.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aff2bd3d585969cc4486bfc69655e862028b689404563e6b549e6a8244f226df"}, + {file = "coverage-7.3.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4353923f38d752ecfbd3f1f20bf7a3546993ae5ecd7c07fd2f25d40b4e54571"}, + {file = "coverage-7.3.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea473c37872f0159294f7073f3fa72f68b03a129799f3533b2bb44d5e9fa4f82"}, + {file = "coverage-7.3.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5214362abf26e254d749fc0c18af4c57b532a4bfde1a057565616dd3b8d7cc94"}, + {file = "coverage-7.3.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f99b7d3f7a7adfa3d11e3a48d1a91bb65739555dd6a0d3fa68aa5852d962e5b1"}, + {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:74397a1263275bea9d736572d4cf338efaade2de9ff759f9c26bcdceb383bb49"}, + {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f154bd866318185ef5865ace5be3ac047b6d1cc0aeecf53bf83fe846f4384d5d"}, + {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e0d84099ea7cba9ff467f9c6f747e3fc3906e2aadac1ce7b41add72e8d0a3712"}, + {file = "coverage-7.3.4-cp310-cp310-win32.whl", hash = "sha256:3f477fb8a56e0c603587b8278d9dbd32e54bcc2922d62405f65574bd76eba78a"}, + {file = "coverage-7.3.4-cp310-cp310-win_amd64.whl", hash = "sha256:c75738ce13d257efbb6633a049fb2ed8e87e2e6c2e906c52d1093a4d08d67c6b"}, + {file = "coverage-7.3.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:997aa14b3e014339d8101b9886063c5d06238848905d9ad6c6eabe533440a9a7"}, + {file = "coverage-7.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a9c5bc5db3eb4cd55ecb8397d8e9b70247904f8eca718cc53c12dcc98e59fc8"}, + {file = "coverage-7.3.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27ee94f088397d1feea3cb524e4313ff0410ead7d968029ecc4bc5a7e1d34fbf"}, + {file = "coverage-7.3.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ce03e25e18dd9bf44723e83bc202114817f3367789052dc9e5b5c79f40cf59d"}, + {file = "coverage-7.3.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85072e99474d894e5df582faec04abe137b28972d5e466999bc64fc37f564a03"}, + {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a877810ef918d0d345b783fc569608804f3ed2507bf32f14f652e4eaf5d8f8d0"}, + {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9ac17b94ab4ca66cf803f2b22d47e392f0977f9da838bf71d1f0db6c32893cb9"}, + {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:36d75ef2acab74dc948d0b537ef021306796da551e8ac8b467810911000af66a"}, + {file = "coverage-7.3.4-cp311-cp311-win32.whl", hash = "sha256:47ee56c2cd445ea35a8cc3ad5c8134cb9bece3a5cb50bb8265514208d0a65928"}, + {file = "coverage-7.3.4-cp311-cp311-win_amd64.whl", hash = "sha256:11ab62d0ce5d9324915726f611f511a761efcca970bd49d876cf831b4de65be5"}, + {file = "coverage-7.3.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:33e63c578f4acce1b6cd292a66bc30164495010f1091d4b7529d014845cd9bee"}, + {file = "coverage-7.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:782693b817218169bfeb9b9ba7f4a9f242764e180ac9589b45112571f32a0ba6"}, + {file = "coverage-7.3.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c4277ddaad9293454da19121c59f2d850f16bcb27f71f89a5c4836906eb35ef"}, + {file = "coverage-7.3.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d892a19ae24b9801771a5a989fb3e850bd1ad2e2b6e83e949c65e8f37bc67a1"}, + {file = "coverage-7.3.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3024ec1b3a221bd10b5d87337d0373c2bcaf7afd86d42081afe39b3e1820323b"}, + {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1c3e9d2bbd6f3f79cfecd6f20854f4dc0c6e0ec317df2b265266d0dc06535f1"}, + {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e91029d7f151d8bf5ab7d8bfe2c3dbefd239759d642b211a677bc0709c9fdb96"}, + {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6879fe41c60080aa4bb59703a526c54e0412b77e649a0d06a61782ecf0853ee1"}, + {file = "coverage-7.3.4-cp312-cp312-win32.whl", hash = "sha256:fd2f8a641f8f193968afdc8fd1697e602e199931012b574194052d132a79be13"}, + {file = "coverage-7.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:d1d0ce6c6947a3a4aa5479bebceff2c807b9f3b529b637e2b33dea4468d75fc7"}, + {file = "coverage-7.3.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:36797b3625d1da885b369bdaaa3b0d9fb8865caed3c2b8230afaa6005434aa2f"}, + {file = "coverage-7.3.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bfed0ec4b419fbc807dec417c401499ea869436910e1ca524cfb4f81cf3f60e7"}, + {file = "coverage-7.3.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f97ff5a9fc2ca47f3383482858dd2cb8ddbf7514427eecf5aa5f7992d0571429"}, + {file = "coverage-7.3.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:607b6c6b35aa49defaebf4526729bd5238bc36fe3ef1a417d9839e1d96ee1e4c"}, + {file = "coverage-7.3.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8e258dcc335055ab59fe79f1dec217d9fb0cdace103d6b5c6df6b75915e7959"}, + {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a02ac7c51819702b384fea5ee033a7c202f732a2a2f1fe6c41e3d4019828c8d3"}, + {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b710869a15b8caf02e31d16487a931dbe78335462a122c8603bb9bd401ff6fb2"}, + {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6a23ae9348a7a92e7f750f9b7e828448e428e99c24616dec93a0720342f241d"}, + {file = "coverage-7.3.4-cp38-cp38-win32.whl", hash = "sha256:758ebaf74578b73f727acc4e8ab4b16ab6f22a5ffd7dd254e5946aba42a4ce76"}, + {file = "coverage-7.3.4-cp38-cp38-win_amd64.whl", hash = "sha256:309ed6a559bc942b7cc721f2976326efbfe81fc2b8f601c722bff927328507dc"}, + {file = "coverage-7.3.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aefbb29dc56317a4fcb2f3857d5bce9b881038ed7e5aa5d3bcab25bd23f57328"}, + {file = "coverage-7.3.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:183c16173a70caf92e2dfcfe7c7a576de6fa9edc4119b8e13f91db7ca33a7923"}, + {file = "coverage-7.3.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a4184dcbe4f98d86470273e758f1d24191ca095412e4335ff27b417291f5964"}, + {file = "coverage-7.3.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93698ac0995516ccdca55342599a1463ed2e2d8942316da31686d4d614597ef9"}, + {file = "coverage-7.3.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb220b3596358a86361139edce40d97da7458412d412e1e10c8e1970ee8c09ab"}, + {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5b14abde6f8d969e6b9dd8c7a013d9a2b52af1235fe7bebef25ad5c8f47fa18"}, + {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:610afaf929dc0e09a5eef6981edb6a57a46b7eceff151947b836d869d6d567c1"}, + {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d6ed790728fb71e6b8247bd28e77e99d0c276dff952389b5388169b8ca7b1c28"}, + {file = "coverage-7.3.4-cp39-cp39-win32.whl", hash = "sha256:c15fdfb141fcf6a900e68bfa35689e1256a670db32b96e7a931cab4a0e1600e5"}, + {file = "coverage-7.3.4-cp39-cp39-win_amd64.whl", hash = "sha256:38d0b307c4d99a7aca4e00cad4311b7c51b7ac38fb7dea2abe0d182dd4008e05"}, + {file = "coverage-7.3.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b1e0f25ae99cf247abfb3f0fac7ae25739e4cd96bf1afa3537827c576b4847e5"}, + {file = "coverage-7.3.4.tar.gz", hash = "sha256:020d56d2da5bc22a0e00a5b0d54597ee91ad72446fa4cf1b97c35022f6b6dbf0"}, ] [package.dependencies] @@ -697,20 +698,19 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.105.0" +version = "0.108.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.105.0-py3-none-any.whl", hash = "sha256:f19ebf6fdc82a3281d10f2cb4774bdfa90238e3b40af3525a0c09fd08ad1c480"}, - {file = "fastapi-0.105.0.tar.gz", hash = "sha256:4d12838819aa52af244580675825e750ad67c9df4614f557a769606af902cf22"}, + {file = "fastapi-0.108.0-py3-none-any.whl", hash = "sha256:8c7bc6d315da963ee4cdb605557827071a9a7f95aeb8fcdd3bde48cdc8764dd7"}, + {file = "fastapi-0.108.0.tar.gz", hash = "sha256:5056e504ac6395bf68493d71fcfc5352fdbd5fda6f88c21f6420d80d81163296"}, ] [package.dependencies] -anyio = ">=3.7.1,<4.0.0" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.27.0,<0.28.0" +starlette = ">=0.29.0,<0.33.0" typing-extensions = ">=4.8.0" [package.extras] @@ -968,74 +968,74 @@ test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre [[package]] name = "greenlet" -version = "3.0.2" +version = "3.0.3" description = "Lightweight in-process concurrent programming" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "greenlet-3.0.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9acd8fd67c248b8537953cb3af8787c18a87c33d4dcf6830e410ee1f95a63fd4"}, - {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:339c0272a62fac7e602e4e6ec32a64ff9abadc638b72f17f6713556ed011d493"}, - {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38878744926cec29b5cc3654ef47f3003f14bfbba7230e3c8492393fe29cc28b"}, - {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b3f0497db77cfd034f829678b28267eeeeaf2fc21b3f5041600f7617139e6773"}, - {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1a8a08de7f68506a38f9a2ddb26bbd1480689e66d788fcd4b5f77e2d9ecfcc"}, - {file = "greenlet-3.0.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89a6f6ddcbef4000cda7e205c4c20d319488ff03db961d72d4e73519d2465309"}, - {file = "greenlet-3.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c1f647fe5b94b51488b314c82fdda10a8756d650cee8d3cd29f657c6031bdf73"}, - {file = "greenlet-3.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9560c580c896030ff9c311c603aaf2282234643c90d1dec738a1d93e3e53cd51"}, - {file = "greenlet-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2e9c5423046eec21f6651268cb674dfba97280701e04ef23d312776377313206"}, - {file = "greenlet-3.0.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1fd25dfc5879a82103b3d9e43fa952e3026c221996ff4d32a9c72052544835d"}, - {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cecfdc950dd25f25d6582952e58521bca749cf3eeb7a9bad69237024308c8196"}, - {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edf7a1daba1f7c54326291a8cde58da86ab115b78c91d502be8744f0aa8e3ffa"}, - {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4cf532bf3c58a862196b06947b1b5cc55503884f9b63bf18582a75228d9950e"}, - {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e79fb5a9fb2d0bd3b6573784f5e5adabc0b0566ad3180a028af99523ce8f6138"}, - {file = "greenlet-3.0.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:006c1028ac0cfcc4e772980cfe73f5476041c8c91d15d64f52482fc571149d46"}, - {file = "greenlet-3.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fefd5eb2c0b1adffdf2802ff7df45bfe65988b15f6b972706a0e55d451bffaea"}, - {file = "greenlet-3.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c0fdb8142742ee68e97c106eb81e7d3e883cc739d9c5f2b28bc38a7bafeb6d1"}, - {file = "greenlet-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:8f8d14a0a4e8c670fbce633d8b9a1ee175673a695475acd838e372966845f764"}, - {file = "greenlet-3.0.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:654b84c9527182036747938b81938f1d03fb8321377510bc1854a9370418ab66"}, - {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd5bc4fde0842ff2b9cf33382ad0b4db91c2582db836793d58d174c569637144"}, - {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c27b142a9080bdd5869a2fa7ebf407b3c0b24bd812db925de90e9afe3c417fd6"}, - {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0df7eed98ea23b20e9db64d46eb05671ba33147df9405330695bcd81a73bb0c9"}, - {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb5d60805057d8948065338be6320d35e26b0a72f45db392eb32b70dd6dc9227"}, - {file = "greenlet-3.0.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0e28f5233d64c693382f66d47c362b72089ebf8ac77df7e12ac705c9fa1163d"}, - {file = "greenlet-3.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e4bfa752b3688d74ab1186e2159779ff4867644d2b1ebf16db14281f0445377"}, - {file = "greenlet-3.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c42bb589e6e9f9d8bdd79f02f044dff020d30c1afa6e84c0b56d1ce8a324553c"}, - {file = "greenlet-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:b2cedf279ca38ef3f4ed0d013a6a84a7fc3d9495a716b84a5fc5ff448965f251"}, - {file = "greenlet-3.0.2-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:6d65bec56a7bc352bcf11b275b838df618651109074d455a772d3afe25390b7d"}, - {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0acadbc3f72cb0ee85070e8d36bd2a4673d2abd10731ee73c10222cf2dd4713c"}, - {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14b5d999aefe9ffd2049ad19079f733c3aaa426190ffecadb1d5feacef8fe397"}, - {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f27aa32466993c92d326df982c4acccd9530fe354e938d9e9deada563e71ce76"}, - {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f34a765c5170c0673eb747213a0275ecc749ab3652bdbec324621ed5b2edaef"}, - {file = "greenlet-3.0.2-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:520fcb53a39ef90f5021c77606952dbbc1da75d77114d69b8d7bded4a8e1a813"}, - {file = "greenlet-3.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1fceb5351ab1601903e714c3028b37f6ea722be6873f46e349a960156c05650"}, - {file = "greenlet-3.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7363756cc439a503505b67983237d1cc19139b66488263eb19f5719a32597836"}, - {file = "greenlet-3.0.2-cp37-cp37m-win32.whl", hash = "sha256:d5547b462b8099b84746461e882a3eb8a6e3f80be46cb6afb8524eeb191d1a30"}, - {file = "greenlet-3.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:950e21562818f9c771989b5b65f990e76f4ac27af66e1bb34634ae67886ede2a"}, - {file = "greenlet-3.0.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d64643317e76b4b41fdba659e7eca29634e5739b8bc394eda3a9127f697ed4b0"}, - {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f9ea7c2c9795549653b6f7569f6bc75d2c7d1f6b2854eb8ce0bc6ec3cb2dd88"}, - {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db4233358d3438369051a2f290f1311a360d25c49f255a6c5d10b5bcb3aa2b49"}, - {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bf77b41798e8417657245b9f3649314218a4a17aefb02bb3992862df32495"}, - {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d0df07a38e41a10dfb62c6fc75ede196572b580f48ee49b9282c65639f3965"}, - {file = "greenlet-3.0.2-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10d247260db20887ae8857c0cbc750b9170f0b067dd7d38fb68a3f2334393bd3"}, - {file = "greenlet-3.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a37ae53cca36823597fd5f65341b6f7bac2dd69ecd6ca01334bb795460ab150b"}, - {file = "greenlet-3.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:80d068e4b6e2499847d916ef64176811ead6bf210a610859220d537d935ec6fd"}, - {file = "greenlet-3.0.2-cp38-cp38-win32.whl", hash = "sha256:b1405614692ac986490d10d3e1a05e9734f473750d4bee3cf7d1286ef7af7da6"}, - {file = "greenlet-3.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8756a94ed8f293450b0e91119eca2a36332deba69feb2f9ca410d35e74eae1e4"}, - {file = "greenlet-3.0.2-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:2c93cd03acb1499ee4de675e1a4ed8eaaa7227f7949dc55b37182047b006a7aa"}, - {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dac09e3c0b78265d2e6d3cbac2d7c48bd1aa4b04a8ffeda3adde9f1688df2c3"}, - {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ee59c4627c8c4bb3e15949fbcd499abd6b7f4ad9e0bfcb62c65c5e2cabe0ec4"}, - {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18fe39d70d482b22f0014e84947c5aaa7211fb8e13dc4cc1c43ed2aa1db06d9a"}, - {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84bef3cfb6b6bfe258c98c519811c240dbc5b33a523a14933a252e486797c90"}, - {file = "greenlet-3.0.2-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aecea0442975741e7d69daff9b13c83caff8c13eeb17485afa65f6360a045765"}, - {file = "greenlet-3.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f260e6c2337871a52161824058923df2bbddb38bc11a5cbe71f3474d877c5bd9"}, - {file = "greenlet-3.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fc14dd9554f88c9c1fe04771589ae24db76cd56c8f1104e4381b383d6b71aff8"}, - {file = "greenlet-3.0.2-cp39-cp39-win32.whl", hash = "sha256:bfcecc984d60b20ffe30173b03bfe9ba6cb671b0be1e95c3e2056d4fe7006590"}, - {file = "greenlet-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:c235131bf59d2546bb3ebaa8d436126267392f2e51b85ff45ac60f3a26549af0"}, - {file = "greenlet-3.0.2.tar.gz", hash = "sha256:1c1129bc47266d83444c85a8e990ae22688cf05fb20d7951fd2866007c2ba9bc"}, + {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, + {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, + {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, + {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, + {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, + {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, + {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, + {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, + {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, + {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, + {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, + {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, + {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, + {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, + {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, + {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, ] [package.extras] -docs = ["Sphinx"] +docs = ["Sphinx", "furo"] test = ["objgraph", "psutil"] [[package]] @@ -1140,14 +1140,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.0" +version = "7.0.1" description = "Read metadata from Python packages" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, - {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] [package.dependencies] @@ -1886,19 +1886,19 @@ files = [ [[package]] name = "pydantic" -version = "2.5.2" +version = "2.5.3" description = "Data validation using Python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, - {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, + {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, + {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.5" +pydantic-core = "2.14.6" typing-extensions = ">=4.6.1" [package.extras] @@ -1906,117 +1906,117 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.5" +version = "2.14.6" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, - {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, - {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, - {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, - {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, - {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, - {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, - {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, - {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, - {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, - {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, - {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, - {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, - {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, - {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, - {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, + {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, + {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, + {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, + {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, + {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, + {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, + {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, + {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, + {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, + {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, + {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, + {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, + {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, + {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, + {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, + {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, + {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, + {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, + {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, + {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, + {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, + {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, + {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, + {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, + {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, + {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, + {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, + {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, + {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, + {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, + {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, + {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, + {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, + {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, + {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, ] [package.dependencies] @@ -2052,14 +2052,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.5" +version = "10.6" description = "Extension pack for Python Markdown." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.5-py3-none-any.whl", hash = "sha256:1f0ca8bb5beff091315f793ee17683bc1390731f6ac4c5eb01e27464b80fe879"}, - {file = "pymdown_extensions-10.5.tar.gz", hash = "sha256:1b60f1e462adbec5a1ed79dac91f666c9c0d241fa294de1989f29d20096cfd0b"}, + {file = "pymdown_extensions-10.6-py3-none-any.whl", hash = "sha256:561eb3a5f3c3c2512952a4d6f5b311aa124b7147bd54a3ea0f36ce030c7e3dd9"}, + {file = "pymdown_extensions-10.6.tar.gz", hash = "sha256:e4531379e0d74b329ff264217ef5b8b1a37bed3afe36f98001b74ecff52215c0"}, ] [package.dependencies] @@ -2249,100 +2249,105 @@ pyyaml = "*" [[package]] name = "regex" -version = "2023.10.3" +version = "2023.12.25" description = "Alternative regular expression module, to replace re." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "regex-2023.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4c34d4f73ea738223a094d8e0ffd6d2c1a1b4c175da34d6b0de3d8d69bee6bcc"}, - {file = "regex-2023.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8f4e49fc3ce020f65411432183e6775f24e02dff617281094ba6ab079ef0915"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cd1bccf99d3ef1ab6ba835308ad85be040e6a11b0977ef7ea8c8005f01a3c29"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81dce2ddc9f6e8f543d94b05d56e70d03a0774d32f6cca53e978dc01e4fc75b8"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c6b4d23c04831e3ab61717a707a5d763b300213db49ca680edf8bf13ab5d91b"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c15ad0aee158a15e17e0495e1e18741573d04eb6da06d8b84af726cfc1ed02ee"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6239d4e2e0b52c8bd38c51b760cd870069f0bdf99700a62cd509d7a031749a55"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4a8bf76e3182797c6b1afa5b822d1d5802ff30284abe4599e1247be4fd6b03be"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9c727bbcf0065cbb20f39d2b4f932f8fa1631c3e01fcedc979bd4f51fe051c5"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3ccf2716add72f80714b9a63899b67fa711b654be3fcdd34fa391d2d274ce767"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:107ac60d1bfdc3edb53be75e2a52aff7481b92817cfdddd9b4519ccf0e54a6ff"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:00ba3c9818e33f1fa974693fb55d24cdc8ebafcb2e4207680669d8f8d7cca79a"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f0a47efb1dbef13af9c9a54a94a0b814902e547b7f21acb29434504d18f36e3a"}, - {file = "regex-2023.10.3-cp310-cp310-win32.whl", hash = "sha256:36362386b813fa6c9146da6149a001b7bd063dabc4d49522a1f7aa65b725c7ec"}, - {file = "regex-2023.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:c65a3b5330b54103e7d21cac3f6bf3900d46f6d50138d73343d9e5b2900b2353"}, - {file = "regex-2023.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90a79bce019c442604662d17bf69df99090e24cdc6ad95b18b6725c2988a490e"}, - {file = "regex-2023.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c7964c2183c3e6cce3f497e3a9f49d182e969f2dc3aeeadfa18945ff7bdd7051"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ef80829117a8061f974b2fda8ec799717242353bff55f8a29411794d635d964"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5addc9d0209a9afca5fc070f93b726bf7003bd63a427f65ef797a931782e7edc"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c148bec483cc4b421562b4bcedb8e28a3b84fcc8f0aa4418e10898f3c2c0eb9b"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d1f21af4c1539051049796a0f50aa342f9a27cde57318f2fc41ed50b0dbc4ac"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b9ac09853b2a3e0d0082104036579809679e7715671cfbf89d83c1cb2a30f58"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ebedc192abbc7fd13c5ee800e83a6df252bec691eb2c4bedc9f8b2e2903f5e2a"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d8a993c0a0ffd5f2d3bda23d0cd75e7086736f8f8268de8a82fbc4bd0ac6791e"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:be6b7b8d42d3090b6c80793524fa66c57ad7ee3fe9722b258aec6d0672543fd0"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4023e2efc35a30e66e938de5aef42b520c20e7eda7bb5fb12c35e5d09a4c43f6"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d47840dc05e0ba04fe2e26f15126de7c755496d5a8aae4a08bda4dd8d646c54"}, - {file = "regex-2023.10.3-cp311-cp311-win32.whl", hash = "sha256:9145f092b5d1977ec8c0ab46e7b3381b2fd069957b9862a43bd383e5c01d18c2"}, - {file = "regex-2023.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:b6104f9a46bd8743e4f738afef69b153c4b8b592d35ae46db07fc28ae3d5fb7c"}, - {file = "regex-2023.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff507ae210371d4b1fe316d03433ac099f184d570a1a611e541923f78f05037"}, - {file = "regex-2023.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be5e22bbb67924dea15039c3282fa4cc6cdfbe0cbbd1c0515f9223186fc2ec5f"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a992f702c9be9c72fa46f01ca6e18d131906a7180950958f766c2aa294d4b41"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7434a61b158be563c1362d9071358f8ab91b8d928728cd2882af060481244c9e"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2169b2dcabf4e608416f7f9468737583ce5f0a6e8677c4efbf795ce81109d7c"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9e908ef5889cda4de038892b9accc36d33d72fb3e12c747e2799a0e806ec841"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12bd4bc2c632742c7ce20db48e0d99afdc05e03f0b4c1af90542e05b809a03d9"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bc72c231f5449d86d6c7d9cc7cd819b6eb30134bb770b8cfdc0765e48ef9c420"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bce8814b076f0ce5766dc87d5a056b0e9437b8e0cd351b9a6c4e1134a7dfbda9"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:ba7cd6dc4d585ea544c1412019921570ebd8a597fabf475acc4528210d7c4a6f"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b0c7d2f698e83f15228ba41c135501cfe7d5740181d5903e250e47f617eb4292"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5a8f91c64f390ecee09ff793319f30a0f32492e99f5dc1c72bc361f23ccd0a9a"}, - {file = "regex-2023.10.3-cp312-cp312-win32.whl", hash = "sha256:ad08a69728ff3c79866d729b095872afe1e0557251da4abb2c5faff15a91d19a"}, - {file = "regex-2023.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:39cdf8d141d6d44e8d5a12a8569d5a227f645c87df4f92179bd06e2e2705e76b"}, - {file = "regex-2023.10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4a3ee019a9befe84fa3e917a2dd378807e423d013377a884c1970a3c2792d293"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76066d7ff61ba6bf3cb5efe2428fc82aac91802844c022d849a1f0f53820502d"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe50b61bab1b1ec260fa7cd91106fa9fece57e6beba05630afe27c71259c59b"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fd88f373cb71e6b59b7fa597e47e518282455c2734fd4306a05ca219a1991b0"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ab05a182c7937fb374f7e946f04fb23a0c0699c0450e9fb02ef567412d2fa3"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dac37cf08fcf2094159922edc7a2784cfcc5c70f8354469f79ed085f0328ebdf"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e54ddd0bb8fb626aa1f9ba7b36629564544954fff9669b15da3610c22b9a0991"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3367007ad1951fde612bf65b0dffc8fd681a4ab98ac86957d16491400d661302"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:16f8740eb6dbacc7113e3097b0a36065a02e37b47c936b551805d40340fb9971"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f4f2ca6df64cbdd27f27b34f35adb640b5d2d77264228554e68deda54456eb11"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:39807cbcbe406efca2a233884e169d056c35aa7e9f343d4e78665246a332f597"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7eece6fbd3eae4a92d7c748ae825cbc1ee41a89bb1c3db05b5578ed3cfcfd7cb"}, - {file = "regex-2023.10.3-cp37-cp37m-win32.whl", hash = "sha256:ce615c92d90df8373d9e13acddd154152645c0dc060871abf6bd43809673d20a"}, - {file = "regex-2023.10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f649fa32fe734c4abdfd4edbb8381c74abf5f34bc0b3271ce687b23729299ed"}, - {file = "regex-2023.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b98b7681a9437262947f41c7fac567c7e1f6eddd94b0483596d320092004533"}, - {file = "regex-2023.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:91dc1d531f80c862441d7b66c4505cd6ea9d312f01fb2f4654f40c6fdf5cc37a"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82fcc1f1cc3ff1ab8a57ba619b149b907072e750815c5ba63e7aa2e1163384a4"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7979b834ec7a33aafae34a90aad9f914c41fd6eaa8474e66953f3f6f7cbd4368"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef71561f82a89af6cfcbee47f0fabfdb6e63788a9258e913955d89fdd96902ab"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd829712de97753367153ed84f2de752b86cd1f7a88b55a3a775eb52eafe8a94"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00e871d83a45eee2f8688d7e6849609c2ca2a04a6d48fba3dff4deef35d14f07"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:706e7b739fdd17cb89e1fbf712d9dc21311fc2333f6d435eac2d4ee81985098c"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cc3f1c053b73f20c7ad88b0d1d23be7e7b3901229ce89f5000a8399746a6e039"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f85739e80d13644b981a88f529d79c5bdf646b460ba190bffcaf6d57b2a9863"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:741ba2f511cc9626b7561a440f87d658aabb3d6b744a86a3c025f866b4d19e7f"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e77c90ab5997e85901da85131fd36acd0ed2221368199b65f0d11bca44549711"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:979c24cbefaf2420c4e377ecd1f165ea08cc3d1fbb44bdc51bccbbf7c66a2cb4"}, - {file = "regex-2023.10.3-cp38-cp38-win32.whl", hash = "sha256:58837f9d221744d4c92d2cf7201c6acd19623b50c643b56992cbd2b745485d3d"}, - {file = "regex-2023.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:c55853684fe08d4897c37dfc5faeff70607a5f1806c8be148f1695be4a63414b"}, - {file = "regex-2023.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2c54e23836650bdf2c18222c87f6f840d4943944146ca479858404fedeb9f9af"}, - {file = "regex-2023.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:69c0771ca5653c7d4b65203cbfc5e66db9375f1078689459fe196fe08b7b4930"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ac965a998e1388e6ff2e9781f499ad1eaa41e962a40d11c7823c9952c77123e"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c0e8fae5b27caa34177bdfa5a960c46ff2f78ee2d45c6db15ae3f64ecadde14"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c56c3d47da04f921b73ff9415fbaa939f684d47293f071aa9cbb13c94afc17d"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ef1e014eed78ab650bef9a6a9cbe50b052c0aebe553fb2881e0453717573f52"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d29338556a59423d9ff7b6eb0cb89ead2b0875e08fe522f3e068b955c3e7b59b"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9c6d0ced3c06d0f183b73d3c5920727268d2201aa0fe6d55c60d68c792ff3588"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:994645a46c6a740ee8ce8df7911d4aee458d9b1bc5639bc968226763d07f00fa"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:66e2fe786ef28da2b28e222c89502b2af984858091675044d93cb50e6f46d7af"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:11175910f62b2b8c055f2b089e0fedd694fe2be3941b3e2633653bc51064c528"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:06e9abc0e4c9ab4779c74ad99c3fc10d3967d03114449acc2c2762ad4472b8ca"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fb02e4257376ae25c6dd95a5aec377f9b18c09be6ebdefa7ad209b9137b73d48"}, - {file = "regex-2023.10.3-cp39-cp39-win32.whl", hash = "sha256:3b2c3502603fab52d7619b882c25a6850b766ebd1b18de3df23b2f939360e1bd"}, - {file = "regex-2023.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:adbccd17dcaff65704c856bd29951c58a1bd4b2b0f8ad6b826dbd543fe740988"}, - {file = "regex-2023.10.3.tar.gz", hash = "sha256:3fef4f844d2290ee0ba57addcec17eec9e3df73f10a2748485dfd6a3a188cc0f"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f"}, + {file = "regex-2023.12.25-cp310-cp310-win32.whl", hash = "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630"}, + {file = "regex-2023.12.25-cp310-cp310-win_amd64.whl", hash = "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4"}, + {file = "regex-2023.12.25-cp311-cp311-win32.whl", hash = "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87"}, + {file = "regex-2023.12.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d"}, + {file = "regex-2023.12.25-cp312-cp312-win32.whl", hash = "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5"}, + {file = "regex-2023.12.25-cp312-cp312-win_amd64.whl", hash = "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232"}, + {file = "regex-2023.12.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39"}, + {file = "regex-2023.12.25-cp37-cp37m-win32.whl", hash = "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c"}, + {file = "regex-2023.12.25-cp37-cp37m-win_amd64.whl", hash = "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2"}, + {file = "regex-2023.12.25-cp38-cp38-win32.whl", hash = "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb"}, + {file = "regex-2023.12.25-cp38-cp38-win_amd64.whl", hash = "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20"}, + {file = "regex-2023.12.25-cp39-cp39-win32.whl", hash = "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9"}, + {file = "regex-2023.12.25-cp39-cp39-win_amd64.whl", hash = "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91"}, + {file = "regex-2023.12.25.tar.gz", hash = "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5"}, ] [[package]] @@ -2389,14 +2394,14 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "69.0.2" +version = "69.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, ] [package.extras] @@ -2517,14 +2522,14 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "starlette" -version = "0.27.0" +version = "0.32.0.post1" description = "The little ASGI library that shines." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, - {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, + {file = "starlette-0.32.0.post1-py3-none-any.whl", hash = "sha256:cd0cb10ddb49313f609cedfac62c8c12e56c7314b66d89bb077ba228bada1b09"}, + {file = "starlette-0.32.0.post1.tar.gz", hash = "sha256:e54e2b7e2fb06dff9eac40133583f10dfa05913f5a85bf26f427c7a40a9a3d02"}, ] [package.dependencies] @@ -2885,4 +2890,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "e3ec7fe7f8ab6b202e1273d2d2edcd76cbb2b65c9ed129e64a7b420fb58f6445" +content-hash = "6b8390a5776272f4be085bc41b7f2414adcec077684273f983e9bbdf12f6a784" diff --git a/pyproject.toml b/pyproject.toml index b5a91e812..6cd17d9a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.8.0" databases = ">=0.3.2,!=0.5.0,!=0.5.1,!=0.5.2,!=0.5.3,<0.6.3" -pydantic = ">=v2.5.2" +pydantic = ">=v2.5.3" SQLAlchemy = ">=1.3.18,<1.4.42" cryptography = { version = ">=35,<42", optional = true } # Async database drivers diff --git a/tests/test_fastapi/test_excludes_with_get_pydantic.py b/tests/test_fastapi/test_excludes_with_get_pydantic.py index 26cd9717f..28bdfc81f 100644 --- a/tests/test_fastapi/test_excludes_with_get_pydantic.py +++ b/tests/test_fastapi/test_excludes_with_get_pydantic.py @@ -126,5 +126,5 @@ async def test_read_main(): "children": [], "id": 2, "name": "test2", - "parent": {"id": 1}, + "parent": {"id": 1, "name": "selfref"}, } diff --git a/tests/test_fastapi/test_relations_with_nested_defaults.py b/tests/test_fastapi/test_relations_with_nested_defaults.py index db4601fdd..cf9a93a29 100644 --- a/tests/test_fastapi/test_relations_with_nested_defaults.py +++ b/tests/test_fastapi/test_relations_with_nested_defaults.py @@ -37,17 +37,16 @@ async def shutdown() -> None: database=database, ) -class Country(ormar.Model): - ormar_config = base_ormar_config.copy( tablename = "countries") +class Country(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="countries") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="Poland") class Author(ormar.Model): - ormar_config = base_ormar_config.copy( tablename = "authors") - + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -56,8 +55,7 @@ class Author(ormar.Model): class Book(ormar.Model): - ormar_config = base_ormar_config.copy( tablename = "books") - + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) From 6ad086b7105ba902b771d44ee1542fab9f511898 Mon Sep 17 00:00:00 2001 From: TouwaStar <30479449+TouwaStar@users.noreply.github.com> Date: Tue, 23 Jan 2024 16:19:34 +0100 Subject: [PATCH 20/95] Getting test suites to pass (#1249) * wip, fixing tests * iteration, fixing some more tests * iteration, fixing some more tests * adhere to comments * adhere to comments * remove unnecessary dict call, re-add getattribute for testing * todo for reverse relationship * adhere to comments, remove prints --- ormar/fields/foreign_key.py | 2 +- ormar/fields/many_to_many.py | 4 ++-- ormar/fields/parsers.py | 6 ++++-- ormar/models/helpers/validation.py | 3 +-- ormar/models/metaclass.py | 26 ++++++++++++------------ ormar/models/newbasemodel.py | 18 +++++++--------- ormar/models/ormar_config.py | 4 ++-- ormar/relations/relation.py | 2 +- tests/test_fastapi/test_binary_fields.py | 10 +++++---- tests/test_fastapi/test_fastapi_docs.py | 1 - 10 files changed, 37 insertions(+), 39 deletions(-) diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index 48e6564db..71e9c1d36 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -373,7 +373,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = self.to._evaluate(globalns, localns, set()) + self.to = self.to._evaluate(globalns, localns) ( self.__type__, self.constraints, diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 9b904923c..a795a8ee6 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -230,7 +230,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = self.to._evaluate(globalns, localns, set()) + self.to = self.to._evaluate(globalns, localns) ( self.__type__, @@ -242,7 +242,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: self.to_pk_only = pk_only_model if self.through.__class__ == ForwardRef: - self.through = self.through._evaluate(globalns, localns, set()) + self.through = self.through._evaluate(globalns, localns) forbid_through_relations(self.through) diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index 31fb22821..ae92c2f95 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -33,8 +33,10 @@ def encode_decimal(value: decimal.Decimal, precision: int = None) -> float: def encode_bytes(value: Union[str, bytes], represent_as_string: bool = False) -> bytes: if represent_as_string: - return value if isinstance(value, bytes) else base64.b64decode(value) - return value if isinstance(value, bytes) else value.encode("utf-8") + value= value if isinstance(value, bytes) else base64.b64decode(value) + else: + value = value if isinstance(value, bytes) else value.encode("utf-8") + return value def encode_json(value: Any) -> Optional[str]: diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index bea703e46..97449b3da 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -1,7 +1,6 @@ import base64 import decimal import numbers -from types import NoneType from typing import ( Any, Callable, @@ -170,7 +169,7 @@ def get_pydantic_example_repr(type_: Any) -> Any: """ if hasattr(type_, "__origin__"): if type_.__origin__ == Union: - values = tuple(get_pydantic_example_repr(x) for x in type_.__args__ if x is not NoneType) + values = tuple(get_pydantic_example_repr(x) for x in type_.__args__ if x is not type(None)) if len(values) == 1: return values[0] return values diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 8944d03e9..9e9e3ce1b 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -265,7 +265,7 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 table_name: str, parent_fields: Dict, attrs: Dict, - meta: ModelMeta, + ormar_config: OrmarConfig, base_class: Type["Model"], ) -> None: """ @@ -292,8 +292,8 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 :type parent_fields: Dict :param attrs: new namespace for class being constructed :type attrs: Dict - :param meta: metaclass of currently created model - :type meta: ModelMeta + :param ormar_config: metaclass of currently created model + :type ormar_config: OrmarConfig """ Field: Type[BaseField] = type( # type: ignore field.__class__.__name__, (ManyToManyField, BaseField), {} @@ -333,7 +333,7 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 # create new table with copied columns but remove foreign keys # they will be populated later in expanding reverse relation # if hasattr(new_meta, "table"): - new_meta.tablename += "_" + meta.tablename + new_meta.tablename += "_" + ormar_config.tablename new_meta.table = None new_meta.model_fields = { name: field @@ -392,20 +392,20 @@ def copy_data_from_parent_model( # noqa: CCR001 model_fields=model_fields, ) parent_fields: Dict = dict() - meta = attrs.get("ormar_config") - if not meta: # pragma: no cover + ormar_config = attrs.get("ormar_config") + if not ormar_config: # pragma: no cover raise ModelDefinitionError( f"Model {curr_class.__name__} declared without ormar_config" ) table_name = ( - meta.tablename - if hasattr(meta, "tablename") and meta.tablename + ormar_config.tablename + if hasattr(ormar_config, "tablename") and ormar_config.tablename else attrs.get("__name__", "").lower() + "s" ) for field_name, field in base_class.ormar_config.model_fields.items(): if ( - hasattr(meta, "exclude_parent_fields") - and field_name in meta.exclude_parent_fields + hasattr(ormar_config, "exclude_parent_fields") + and field_name in ormar_config.exclude_parent_fields ): continue if field.is_multi: @@ -416,7 +416,7 @@ def copy_data_from_parent_model( # noqa: CCR001 table_name=table_name, parent_fields=parent_fields, attrs=attrs, - meta=meta, + ormar_config=ormar_config, base_class=base_class, # type: ignore ) @@ -574,9 +574,9 @@ def __new__( # type: ignore # noqa: CCR001 name: str, bases: Any, attrs: dict, - __pydantic_generic_metadata__: PydanticGenericMetadata | None = None, + __pydantic_generic_metadata__: Union[PydanticGenericMetadata, None] = None, __pydantic_reset_parent_namespace__: bool = True, - _create_model_module: str | None = None, + _create_model_module: Union[str, None] = None, **kwargs ) -> "ModelMetaclass": """ diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index b0317a868..d3aa9da25 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -20,7 +20,7 @@ import databases import pydantic import sqlalchemy -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict import ormar # noqa I100 @@ -152,7 +152,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # type: ignore values = new_kwargs object.__setattr__(self, "__dict__", values) object.__setattr__(self, "__pydantic_fields_set__", fields_set) - # add back through fields new_kwargs.update(through_tmp_dict) model_fields = object.__getattribute__(self, "ormar_config").model_fields @@ -162,9 +161,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # type: ignore new_kwargs.get(related), self, to_register=True ) - if hasattr(self, "_init_private_attributes"): - # introduced in pydantic 1.7 - self._init_private_attributes() def __setattr__(self, name: str, value: Any) -> None: # noqa CCR001 """ @@ -208,17 +204,17 @@ def __getattr__(self, item: str) -> Any: return None return super().__getattr__(item) - def __getattribute__(self, item: str) -> Any: - if item == "__dict__": - print(item, sys._getframe(1)) - return super().__getattribute__(item) - def __getstate__(self) -> Dict[Any, Any]: state = super().__getstate__() self_dict = self.dict() state["__dict__"].update(**self_dict) return state + def __getattribute__(self, item: str) -> Any: + if item == "__dict__": + print(item, sys._getframe(1)) + return super().__getattribute__(item) + def __setstate__(self, state: Dict[Any, Any]) -> None: relations = { k: v @@ -293,7 +289,7 @@ def _process_kwargs(self, kwargs: Dict) -> Tuple[Dict, Dict]: # noqa: CCR001 Removes property_fields - Checks if field is in the model fields or pydatnic fields. + Checks if field is in the model fields or pydantic fields. Nullifies fields that should be excluded. diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index ab6bed4a2..17702e693 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -18,7 +18,7 @@ def __init__( metadata: Optional[sqlalchemy.MetaData] = None, database: Optional[databases.Database] = None, tablename: Optional[str] = None, - order_by: Optional[list[str]] = None, + order_by: Optional[List[str]] = None, abstract: bool = False, exclude_parent_fields: Optional[List[str]] = None, queryset_class: Type[QuerySet] = QuerySet, @@ -50,7 +50,7 @@ def copy( metadata: Optional[sqlalchemy.MetaData] = None, database: Optional[databases.Database] = None, tablename: Optional[str] = None, - order_by: Optional[list[str]] = None, + order_by: Optional[List[str]] = None, abstract: Optional[bool] = None, exclude_parent_fields: Optional[List[str]] = None, queryset_class: Optional[Type[QuerySet]] = None, diff --git a/ormar/relations/relation.py b/ormar/relations/relation.py index 982ac31bd..e782d209c 100644 --- a/ormar/relations/relation.py +++ b/ormar/relations/relation.py @@ -165,7 +165,7 @@ def add(self, child: "Model") -> None: self._populate_owner_side_dict(rel=rel, child=child) self._owner.__dict__[relation_name] = rel - def _populate_owner_side_dict(self, rel:List["Model"], child: "Model") -> None: + def _populate_owner_side_dict(self, rel: List["Model"], child: "Model") -> None: try: if child not in rel: rel.append(child) diff --git a/tests/test_fastapi/test_binary_fields.py b/tests/test_fastapi/test_binary_fields.py index 0564216de..354941006 100644 --- a/tests/test_fastapi/test_binary_fields.py +++ b/tests/test_fastapi/test_binary_fields.py @@ -1,5 +1,4 @@ import base64 -import json import uuid from enum import Enum from typing import List @@ -37,7 +36,7 @@ async def shutdown() -> None: await database_.disconnect() -blob3 = b"\xc3\x28" +blob3 = b"\xc3\x83\x28" blob4 = b"\xf0\x28\x8c\x28" blob5 = b"\xee" blob6 = b"\xff" @@ -94,9 +93,12 @@ async def test_read_main(): ) assert response.status_code == 200 response = await client.get("/things") - assert response.json()[0]["bt"] == base64.b64encode(blob3).decode() - thing = BinaryThing(**response.json()[0]) + assert response.json()[0]["bt"] == blob3.decode() + resp_json = response.json() + resp_json[0]["bt"] = resp_json[0]["bt"].encode() + thing = BinaryThing(**resp_json[0]) assert thing.__dict__["bt"] == blob3 + assert thing.bt == base64.b64encode(blob3).decode() def test_schema(): diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index 085da98ad..253318845 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -5,7 +5,6 @@ import pydantic import pytest import sqlalchemy -import uvicorn from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient From baac771998f579dcd7d063a2c4a56815c59c9720 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 24 Jan 2024 15:09:00 +0100 Subject: [PATCH 21/95] solve circular refs --- ormar/fields/foreign_key.py | 9 +++-- ormar/fields/many_to_many.py | 4 +- ormar/models/helpers/relations.py | 38 ++++++++++++++++++- ormar/models/newbasemodel.py | 5 --- .../test_relations_with_nested_defaults.py | 6 +-- 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index 71e9c1d36..aee2462be 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -373,7 +373,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = self.to._evaluate(globalns, localns) + self.to = self.to._evaluate(globalns, localns, set()) ( self.__type__, self.constraints, @@ -453,9 +453,12 @@ def _construct_model_from_dict( :rtype: Model """ pk_only_model = None + keys = set(value.keys()) + own_keys = keys - self.to.extract_related_names() if ( - len(value.keys()) == 1 - and list(value.keys())[0] == self.to.ormar_config.pkname + len(own_keys) == 1 + and list(own_keys)[0] == self.to.ormar_config.pkname + and not self.is_through ): value["__pk_only__"] = True pk_only_model = self.to_pk_only(**value) diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index a795a8ee6..9b904923c 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -230,7 +230,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = self.to._evaluate(globalns, localns) + self.to = self.to._evaluate(globalns, localns, set()) ( self.__type__, @@ -242,7 +242,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: self.to_pk_only = pk_only_model if self.through.__class__ == ForwardRef: - self.through = self.through._evaluate(globalns, localns) + self.through = self.through._evaluate(globalns, localns, set()) forbid_through_relations(self.through) diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 44d9997bf..5b804d6e3 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -1,9 +1,11 @@ import copy import inspect -from typing import List, TYPE_CHECKING, Optional, Type, Union, cast, Dict +from typing import List, TYPE_CHECKING, Optional, Type, Union, cast, Dict, Any -from pydantic import BaseModel, create_model +from pydantic import BaseModel, create_model, field_serializer +from pydantic._internal._decorators import Decorator, DecoratorInfos from pydantic.fields import FieldInfo +from pydantic_core.core_schema import SerializerFunctionWrapHandler import ormar from ormar import ForeignKey, ManyToMany @@ -147,10 +149,42 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: model_field.to.model_fields[related_name] = FieldInfo.from_annotated_attribute( annotation=field_type, default=None ) + add_field_serializer_for_reverse_relations(to_model=model_field.to, related_name=related_name) model_field.to.model_rebuild(force=True) setattr(model_field.to, related_name, RelationDescriptor(name=related_name)) +def add_field_serializer_for_reverse_relations(to_model: "Model", related_name: str) -> None: + def serialize(self, children: List['BaseModel'], handler: SerializerFunctionWrapHandler) -> Any: + """ + Serialize a list of nodes, handling circular references by excluding the children. + """ + try: + return handler(children) + except ValueError as exc: + if not str(exc).startswith('Circular reference'): + raise exc + + result = [] + for child in children: + try: + serialized = handler([child]) + except ValueError as exc: + if not str(exc).startswith('Circular reference'): + raise exc + result.append({child.ormar_config.pkname: child.pk}) + else: + result.append(serialized) + return result + + decorator = field_serializer(related_name, mode="wrap", check_fields=False)(serialize) + setattr(to_model, f"serialize_{related_name}", decorator) + DecoratorInfos.build(to_model) + # to_model.__pydantic_decorators__.field_serializers["serialize"] = Decorator.build( + # to_model, cls_var_name="serialize", shim=decorator.shim, info=decorator.decorator_info + # ) + + def replace_models_with_copy( annotation: Type, source_model_field: Optional[str] = None ) -> Type: diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index d3aa9da25..e773aa891 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -210,11 +210,6 @@ def __getstate__(self) -> Dict[Any, Any]: state["__dict__"].update(**self_dict) return state - def __getattribute__(self, item: str) -> Any: - if item == "__dict__": - print(item, sys._getframe(1)) - return super().__getattribute__(item) - def __setstate__(self, state: Dict[Any, Any]) -> None: relations = { k: v diff --git a/tests/test_fastapi/test_relations_with_nested_defaults.py b/tests/test_fastapi/test_relations_with_nested_defaults.py index cf9a93a29..1c5bb474a 100644 --- a/tests/test_fastapi/test_relations_with_nested_defaults.py +++ b/tests/test_fastapi/test_relations_with_nested_defaults.py @@ -99,7 +99,7 @@ async def test_related_with_defaults(sample_data): async with client as client, LifespanManager(app): response = await client.get("/books/1") assert response.json() == { - "author": {"id": 1}, + "author": {"id": 1, "books": [{"id": 1}]}, "id": 1, "title": "Bug caused by default value", "year": 2021, @@ -109,9 +109,9 @@ async def test_related_with_defaults(sample_data): assert response.json() == { "author": { "books": [ - {"id": 1, "title": "Bug caused by default value", "year": 2021} + {"id": 1} ], - "country": {"id": 1}, + "country": {"id": 1, 'authors': [{'id': 1}]}, "id": 1, "name": "bug", "rating": 5, From 8a799c1664464623948113055601ea786af6be9d Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 25 Jan 2024 14:47:59 +0100 Subject: [PATCH 22/95] all tests pass :tada: --- ormar/fields/foreign_key.py | 1 + ormar/models/helpers/relations.py | 3 -- ormar/models/metaclass.py | 24 ++++++++++++ .../test_excludes_with_get_pydantic.py | 18 +++++++-- tests/test_fastapi/test_fastapi_docs.py | 2 +- .../test_relations_with_nested_defaults.py | 39 +++++++++---------- 6 files changed, 59 insertions(+), 28 deletions(-) diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index aee2462be..da2657bec 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -458,6 +458,7 @@ def _construct_model_from_dict( if ( len(own_keys) == 1 and list(own_keys)[0] == self.to.ormar_config.pkname + and value.get(self.to.ormar_config.pkname) is not None and not self.is_through ): value["__pk_only__"] = True diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 5b804d6e3..8bd373d26 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -180,9 +180,6 @@ def serialize(self, children: List['BaseModel'], handler: SerializerFunctionWrap decorator = field_serializer(related_name, mode="wrap", check_fields=False)(serialize) setattr(to_model, f"serialize_{related_name}", decorator) DecoratorInfos.build(to_model) - # to_model.__pydantic_decorators__.field_serializers["serialize"] = Decorator.build( - # to_model, cls_var_name="serialize", shim=decorator.shim, info=decorator.decorator_info - # ) def replace_models_with_copy( diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 9e9e3ce1b..b979d2235 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -16,9 +16,11 @@ import databases import pydantic import sqlalchemy +from pydantic import field_serializer from pydantic._internal._generics import PydanticGenericMetadata from pydantic._internal._model_construction import complete_model_class from pydantic.fields import ComputedFieldInfo, FieldInfo +from pydantic_core.core_schema import SerializerFunctionWrapHandler from sqlalchemy.sql.schema import ColumnCollectionConstraint import ormar # noqa I100 @@ -567,6 +569,23 @@ def add_field_descriptor( else: setattr(new_model, name, PydanticDescriptor(name=name)) +def get_serializer(): + def serialize(self, value: Optional[pydantic.BaseModel], handler: SerializerFunctionWrapHandler) -> Any: + """ + Serialize a value if it's not expired weak reference. + """ + try: + return handler(value) + except ReferenceError: + return None + except ValueError as exc: + if not str(exc).startswith('Circular reference'): + raise exc + return {value.ormar_config.pkname: value.pk} + + return serialize + + class ModelMetaclass(pydantic._internal._model_construction.ModelMetaclass): def __new__( # type: ignore # noqa: CCR001 @@ -622,6 +641,11 @@ def __new__( # type: ignore # noqa: CCR001 if "ormar_config" in attrs: attrs["model_config"]["ignored_types"] = (OrmarConfig,) attrs["model_config"]["from_attributes"] = True + for field_name, field in model_fields.items(): + if field.is_relation: + decorator = field_serializer(field_name, mode="wrap", check_fields=False)(get_serializer()) + attrs[f"serialize_{field_name}"] = decorator + new_model = super().__new__( mcs, # type: ignore name, diff --git a/tests/test_fastapi/test_excludes_with_get_pydantic.py b/tests/test_fastapi/test_excludes_with_get_pydantic.py index 28bdfc81f..6699f4a8f 100644 --- a/tests/test_fastapi/test_excludes_with_get_pydantic.py +++ b/tests/test_fastapi/test_excludes_with_get_pydantic.py @@ -51,9 +51,9 @@ async def create_category(category: Category): response_model=SelfRef.get_pydantic(exclude={"parent", "children__name"}), ) async def create_selfref( - selfref: SelfRef.get_pydantic( # type: ignore - exclude={"children__name"} # noqa: F821 - ), + selfref: SelfRef.get_pydantic( # type: ignore + exclude={"children__name"} # noqa: F821 + ), ): selfr = SelfRef(**selfref.dict()) await selfr.save() @@ -126,5 +126,15 @@ async def test_read_main(): "children": [], "id": 2, "name": "test2", - "parent": {"id": 1, "name": "selfref"}, + "parent": {"id": 1}, + } + + response = await client.get("/selfrefs/1/") + assert response.status_code == 200 + check_children = SelfRef(**response.json()) + assert check_children.dict() == { + 'children': [{'id': 2, 'name': 'test2'}], + 'id': 1, + 'name': 'test', + 'parent': None } diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index 253318845..90ea17d9a 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -143,7 +143,7 @@ def test_schema_modification(): } schema = Category.model_json_schema() - assert schema["example"] == { + assert schema["$defs"]["Category"]["example"] == { "id": 0, "name": "string", "items": [ diff --git a/tests/test_fastapi/test_relations_with_nested_defaults.py b/tests/test_fastapi/test_relations_with_nested_defaults.py index 1c5bb474a..d8027d411 100644 --- a/tests/test_fastapi/test_relations_with_nested_defaults.py +++ b/tests/test_fastapi/test_relations_with_nested_defaults.py @@ -98,25 +98,24 @@ async def test_related_with_defaults(sample_data): client = AsyncClient(app=app, base_url="http://testserver") async with client as client, LifespanManager(app): response = await client.get("/books/1") - assert response.json() == { - "author": {"id": 1, "books": [{"id": 1}]}, - "id": 1, - "title": "Bug caused by default value", - "year": 2021, - } + assert response.json() == {'author': {'books': [{'author': {'id': 1}, + 'id': 1, + 'title': 'Bug caused by default value', + 'year': 2021}], + 'id': 1}, + 'id': 1, + 'title': 'Bug caused by default value', + 'year': 2021} response = await client.get("/books_with_author/1") - assert response.json() == { - "author": { - "books": [ - {"id": 1} - ], - "country": {"id": 1, 'authors': [{'id': 1}]}, - "id": 1, - "name": "bug", - "rating": 5, - }, - "id": 1, - "title": "Bug caused by default value", - "year": 2021, - } + assert response.json() == {'author': {'books': [{'author': {'id': 1}, + 'id': 1, + 'title': 'Bug caused by default value', + 'year': 2021}], + 'country': {'authors': [{'id': 1}], 'id': 1}, + 'id': 1, + 'name': 'bug', + 'rating': 5}, + 'id': 1, + 'title': 'Bug caused by default value', + 'year': 2021} From a73700189c93ac070723c50bb74ff8762240052d Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 25 Jan 2024 14:51:47 +0100 Subject: [PATCH 23/95] remove 3.7 from tests --- .github/workflows/test-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 6d10e3f34..08d361380 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -17,7 +17,7 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'collerek/ormar' strategy: matrix: - python-version: [3.7, 3.8, 3.9, "3.10", 3.11] + python-version: [3.8, 3.9, "3.10", 3.11] fail-fast: false services: mysql: From c5a10fb23b5c3708986cadc2763639b645d4f97c Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 25 Jan 2024 15:05:10 +0100 Subject: [PATCH 24/95] add lint and type check jobs --- .github/workflows/lint.yml | 31 ++ .github/workflows/type-check.yml | 31 ++ Makefile | 14 +- poetry.lock | 867 ++++++++----------------------- pyproject.toml | 19 +- 5 files changed, 305 insertions(+), 657 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/type-check.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..94455542f --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,31 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: lint + +on: + push: + branches-ignore: + - 'gh-pages' + pull_request: + branches: [ master ] + +jobs: + lint: + name: "Python ${{ matrix.python-version }}" + runs-on: ubuntu-latest + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'collerek/ormar' + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Install dependencies + run: | + python -m pip install poetry==1.4.2 + poetry install --extras "all" + env: + POETRY_VIRTUALENVS_CREATE: false + - name: Lint + run: make style diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml new file mode 100644 index 000000000..c8d3084fe --- /dev/null +++ b/.github/workflows/type-check.yml @@ -0,0 +1,31 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: type_check + +on: + push: + branches-ignore: + - 'gh-pages' + pull_request: + branches: [ master ] + +jobs: + lint: + name: "Python ${{ matrix.python-version }}" + runs-on: ubuntu-latest + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'collerek/ormar' + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Install dependencies + run: | + python -m pip install poetry==1.4.2 + poetry install --extras "all" + env: + POETRY_VIRTUALENVS_CREATE: false + - name: Lint + run: make type_check diff --git a/Makefile b/Makefile index 5aa089de3..2bf7b9301 100644 --- a/Makefile +++ b/Makefile @@ -21,12 +21,14 @@ test: coverage: pytest --cov=ormar --cov=tests --cov-fail-under=100 --cov-report=term-missing -black: - black ormar tests + +fmt: + poetry run python -m black --line-length=120 . + +type_check: + mkdir -p .mypy_cache && poetry run python -m mypy . --ignore-missing-imports --install-types --non-interactive lint: - black ormar tests - flake8 ormar + poetry run python -m ruff . --fix -mypy: - mypy ormar tests +style: fmt lint \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 748f69fb0..94586c76a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -107,18 +107,6 @@ files = [ [package.dependencies] sniffio = "*" -[[package]] -name = "astpretty" -version = "3.0.0" -description = "Pretty print the output of python stdlib `ast.parse`." -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "astpretty-3.0.0-py2.py3-none-any.whl", hash = "sha256:15bfd47593667169485a1fa7938b8de9445b11057d6f2b6e214b2f70667f94b6"}, - {file = "astpretty-3.0.0.tar.gz", hash = "sha256:b08c95f32e5994454ea99882ff3c4a0afc8254c38998a0ed4b479dba448dc581"}, -] - [[package]] name = "async-timeout" version = "4.0.3" @@ -182,49 +170,6 @@ dev = ["Cython (>=0.29.24,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "flake8 (>=5.0.4 docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] test = ["flake8 (>=5.0.4,<5.1.0)", "uvloop (>=0.15.3)"] -[[package]] -name = "attrs" -version = "23.1.0" -description = "Classes Without Boilerplate" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] - -[[package]] -name = "bandit" -version = "1.7.6" -description = "Security oriented static analyser for python code." -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "bandit-1.7.6-py3-none-any.whl", hash = "sha256:36da17c67fc87579a5d20c323c8d0b1643a890a2b93f00b3d1229966624694ff"}, - {file = "bandit-1.7.6.tar.gz", hash = "sha256:72ce7bc9741374d96fb2f1c9a8960829885f1243ffde743de70a19cee353e8f3"}, -] - -[package.dependencies] -colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} -GitPython = ">=3.1.30" -PyYAML = ">=5.3.1" -rich = "*" -stevedore = ">=1.20.0" - -[package.extras] -test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "tomli (>=1.1.0)"] -toml = ["tomli (>=1.1.0)"] -yaml = ["PyYAML"] - [[package]] name = "black" version = "23.12.1" @@ -492,20 +437,6 @@ files = [ coverage = "*" requests = ">=2.7.9" -[[package]] -name = "cognitive-complexity" -version = "1.3.0" -description = "Library to calculate Python functions cognitive complexity via code" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "cognitive_complexity-1.3.0.tar.gz", hash = "sha256:a0cfbd47dee0b19f4056f892389f501694b205c3af69fb703cc744541e03dde5"}, -] - -[package.dependencies] -setuptools = "*" - [[package]] name = "colorama" version = "0.4.6" @@ -520,64 +451,64 @@ files = [ [[package]] name = "coverage" -version = "7.3.4" +version = "7.4.0" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aff2bd3d585969cc4486bfc69655e862028b689404563e6b549e6a8244f226df"}, - {file = "coverage-7.3.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4353923f38d752ecfbd3f1f20bf7a3546993ae5ecd7c07fd2f25d40b4e54571"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea473c37872f0159294f7073f3fa72f68b03a129799f3533b2bb44d5e9fa4f82"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5214362abf26e254d749fc0c18af4c57b532a4bfde1a057565616dd3b8d7cc94"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f99b7d3f7a7adfa3d11e3a48d1a91bb65739555dd6a0d3fa68aa5852d962e5b1"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:74397a1263275bea9d736572d4cf338efaade2de9ff759f9c26bcdceb383bb49"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f154bd866318185ef5865ace5be3ac047b6d1cc0aeecf53bf83fe846f4384d5d"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e0d84099ea7cba9ff467f9c6f747e3fc3906e2aadac1ce7b41add72e8d0a3712"}, - {file = "coverage-7.3.4-cp310-cp310-win32.whl", hash = "sha256:3f477fb8a56e0c603587b8278d9dbd32e54bcc2922d62405f65574bd76eba78a"}, - {file = "coverage-7.3.4-cp310-cp310-win_amd64.whl", hash = "sha256:c75738ce13d257efbb6633a049fb2ed8e87e2e6c2e906c52d1093a4d08d67c6b"}, - {file = "coverage-7.3.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:997aa14b3e014339d8101b9886063c5d06238848905d9ad6c6eabe533440a9a7"}, - {file = "coverage-7.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a9c5bc5db3eb4cd55ecb8397d8e9b70247904f8eca718cc53c12dcc98e59fc8"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27ee94f088397d1feea3cb524e4313ff0410ead7d968029ecc4bc5a7e1d34fbf"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ce03e25e18dd9bf44723e83bc202114817f3367789052dc9e5b5c79f40cf59d"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85072e99474d894e5df582faec04abe137b28972d5e466999bc64fc37f564a03"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a877810ef918d0d345b783fc569608804f3ed2507bf32f14f652e4eaf5d8f8d0"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9ac17b94ab4ca66cf803f2b22d47e392f0977f9da838bf71d1f0db6c32893cb9"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:36d75ef2acab74dc948d0b537ef021306796da551e8ac8b467810911000af66a"}, - {file = "coverage-7.3.4-cp311-cp311-win32.whl", hash = "sha256:47ee56c2cd445ea35a8cc3ad5c8134cb9bece3a5cb50bb8265514208d0a65928"}, - {file = "coverage-7.3.4-cp311-cp311-win_amd64.whl", hash = "sha256:11ab62d0ce5d9324915726f611f511a761efcca970bd49d876cf831b4de65be5"}, - {file = "coverage-7.3.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:33e63c578f4acce1b6cd292a66bc30164495010f1091d4b7529d014845cd9bee"}, - {file = "coverage-7.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:782693b817218169bfeb9b9ba7f4a9f242764e180ac9589b45112571f32a0ba6"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c4277ddaad9293454da19121c59f2d850f16bcb27f71f89a5c4836906eb35ef"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d892a19ae24b9801771a5a989fb3e850bd1ad2e2b6e83e949c65e8f37bc67a1"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3024ec1b3a221bd10b5d87337d0373c2bcaf7afd86d42081afe39b3e1820323b"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1c3e9d2bbd6f3f79cfecd6f20854f4dc0c6e0ec317df2b265266d0dc06535f1"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e91029d7f151d8bf5ab7d8bfe2c3dbefd239759d642b211a677bc0709c9fdb96"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6879fe41c60080aa4bb59703a526c54e0412b77e649a0d06a61782ecf0853ee1"}, - {file = "coverage-7.3.4-cp312-cp312-win32.whl", hash = "sha256:fd2f8a641f8f193968afdc8fd1697e602e199931012b574194052d132a79be13"}, - {file = "coverage-7.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:d1d0ce6c6947a3a4aa5479bebceff2c807b9f3b529b637e2b33dea4468d75fc7"}, - {file = "coverage-7.3.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:36797b3625d1da885b369bdaaa3b0d9fb8865caed3c2b8230afaa6005434aa2f"}, - {file = "coverage-7.3.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bfed0ec4b419fbc807dec417c401499ea869436910e1ca524cfb4f81cf3f60e7"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f97ff5a9fc2ca47f3383482858dd2cb8ddbf7514427eecf5aa5f7992d0571429"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:607b6c6b35aa49defaebf4526729bd5238bc36fe3ef1a417d9839e1d96ee1e4c"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8e258dcc335055ab59fe79f1dec217d9fb0cdace103d6b5c6df6b75915e7959"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a02ac7c51819702b384fea5ee033a7c202f732a2a2f1fe6c41e3d4019828c8d3"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b710869a15b8caf02e31d16487a931dbe78335462a122c8603bb9bd401ff6fb2"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6a23ae9348a7a92e7f750f9b7e828448e428e99c24616dec93a0720342f241d"}, - {file = "coverage-7.3.4-cp38-cp38-win32.whl", hash = "sha256:758ebaf74578b73f727acc4e8ab4b16ab6f22a5ffd7dd254e5946aba42a4ce76"}, - {file = "coverage-7.3.4-cp38-cp38-win_amd64.whl", hash = "sha256:309ed6a559bc942b7cc721f2976326efbfe81fc2b8f601c722bff927328507dc"}, - {file = "coverage-7.3.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aefbb29dc56317a4fcb2f3857d5bce9b881038ed7e5aa5d3bcab25bd23f57328"}, - {file = "coverage-7.3.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:183c16173a70caf92e2dfcfe7c7a576de6fa9edc4119b8e13f91db7ca33a7923"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a4184dcbe4f98d86470273e758f1d24191ca095412e4335ff27b417291f5964"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93698ac0995516ccdca55342599a1463ed2e2d8942316da31686d4d614597ef9"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb220b3596358a86361139edce40d97da7458412d412e1e10c8e1970ee8c09ab"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5b14abde6f8d969e6b9dd8c7a013d9a2b52af1235fe7bebef25ad5c8f47fa18"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:610afaf929dc0e09a5eef6981edb6a57a46b7eceff151947b836d869d6d567c1"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d6ed790728fb71e6b8247bd28e77e99d0c276dff952389b5388169b8ca7b1c28"}, - {file = "coverage-7.3.4-cp39-cp39-win32.whl", hash = "sha256:c15fdfb141fcf6a900e68bfa35689e1256a670db32b96e7a931cab4a0e1600e5"}, - {file = "coverage-7.3.4-cp39-cp39-win_amd64.whl", hash = "sha256:38d0b307c4d99a7aca4e00cad4311b7c51b7ac38fb7dea2abe0d182dd4008e05"}, - {file = "coverage-7.3.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b1e0f25ae99cf247abfb3f0fac7ae25739e4cd96bf1afa3537827c576b4847e5"}, - {file = "coverage-7.3.4.tar.gz", hash = "sha256:020d56d2da5bc22a0e00a5b0d54597ee91ad72446fa4cf1b97c35022f6b6dbf0"}, + {file = "coverage-7.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a"}, + {file = "coverage-7.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43"}, + {file = "coverage-7.4.0-cp310-cp310-win32.whl", hash = "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451"}, + {file = "coverage-7.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137"}, + {file = "coverage-7.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca"}, + {file = "coverage-7.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26"}, + {file = "coverage-7.4.0-cp311-cp311-win32.whl", hash = "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614"}, + {file = "coverage-7.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590"}, + {file = "coverage-7.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143"}, + {file = "coverage-7.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa"}, + {file = "coverage-7.4.0-cp312-cp312-win32.whl", hash = "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450"}, + {file = "coverage-7.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0"}, + {file = "coverage-7.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e"}, + {file = "coverage-7.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105"}, + {file = "coverage-7.4.0-cp38-cp38-win32.whl", hash = "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2"}, + {file = "coverage-7.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555"}, + {file = "coverage-7.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42"}, + {file = "coverage-7.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f"}, + {file = "coverage-7.4.0-cp39-cp39-win32.whl", hash = "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932"}, + {file = "coverage-7.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e"}, + {file = "coverage-7.4.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6"}, + {file = "coverage-7.4.0.tar.gz", hash = "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e"}, ] [package.dependencies] @@ -698,19 +629,19 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.108.0" +version = "0.109.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.108.0-py3-none-any.whl", hash = "sha256:8c7bc6d315da963ee4cdb605557827071a9a7f95aeb8fcdd3bde48cdc8764dd7"}, - {file = "fastapi-0.108.0.tar.gz", hash = "sha256:5056e504ac6395bf68493d71fcfc5352fdbd5fda6f88c21f6420d80d81163296"}, + {file = "fastapi-0.109.0-py3-none-any.whl", hash = "sha256:8c77515984cd8e8cfeb58364f8cc7a28f0692088475e2614f7bf03275eba9093"}, + {file = "fastapi-0.109.0.tar.gz", hash = "sha256:b978095b9ee01a5cf49b19f4bc1ac9b8ca83aa076e770ef8fd9af09a2b88d191"}, ] [package.dependencies] pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.29.0,<0.33.0" +starlette = ">=0.35.0,<0.36.0" typing-extensions = ">=4.8.0" [package.extras] @@ -733,188 +664,6 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] -[[package]] -name = "flake8" -version = "3.9.2" -description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, - {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, -] - -[package.dependencies] -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.7.0,<2.8.0" -pyflakes = ">=2.3.0,<2.4.0" - -[[package]] -name = "flake8-bandit" -version = "3.0.0" -description = "Automated security testing with bandit and flake8." -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "flake8_bandit-3.0.0-py2.py3-none-any.whl", hash = "sha256:61b617f4f7cdaa0e2b1e6bf7b68afb2b619a227bb3e3ae00dd36c213bd17900a"}, - {file = "flake8_bandit-3.0.0.tar.gz", hash = "sha256:54d19427e6a8d50322a7b02e1841c0a7c22d856975f3459803320e0e18e2d6a1"}, -] - -[package.dependencies] -bandit = ">=1.7.3" -flake8 = "*" -flake8-polyfill = "*" -pycodestyle = "*" - -[[package]] -name = "flake8-black" -version = "0.3.6" -description = "flake8 plugin to call black as a code style validator" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8-black-0.3.6.tar.gz", hash = "sha256:0dfbca3274777792a5bcb2af887a4cad72c72d0e86c94e08e3a3de151bb41c34"}, - {file = "flake8_black-0.3.6-py3-none-any.whl", hash = "sha256:fe8ea2eca98d8a504f22040d9117347f6b367458366952862ac3586e7d4eeaca"}, -] - -[package.dependencies] -black = ">=22.1.0" -flake8 = ">=3" -tomli = {version = "*", markers = "python_version < \"3.11\""} - -[package.extras] -develop = ["build", "twine"] - -[[package]] -name = "flake8-bugbear" -version = "23.3.12" -description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8-bugbear-23.3.12.tar.gz", hash = "sha256:e3e7f74c8a49ad3794a7183353026dabd68c74030d5f46571f84c1fb0eb79363"}, - {file = "flake8_bugbear-23.3.12-py3-none-any.whl", hash = "sha256:beb5c7efcd7ccc2039ef66a77bb8db925e7be3531ff1cb4d0b7030d0e2113d72"}, -] - -[package.dependencies] -attrs = ">=19.2.0" -flake8 = ">=3.0.0" - -[package.extras] -dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"] - -[[package]] -name = "flake8-builtins" -version = "2.2.0" -description = "Check for python builtins being used as variables or parameters" -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "flake8_builtins-2.2.0-py3-none-any.whl", hash = "sha256:7ee5766d9c60e5d579dfda84e65c6d0e6c26005f6f59cb9bf722462d7987a807"}, - {file = "flake8_builtins-2.2.0.tar.gz", hash = "sha256:392d5af3a0720c5a863aa93dc47f48c879081345a143fe9f20d995fe9ff5686a"}, -] - -[package.dependencies] -flake8 = "*" - -[package.extras] -test = ["pytest"] - -[[package]] -name = "flake8-cognitive-complexity" -version = "0.1.0" -description = "An extension for flake8 that validates cognitive functions complexity" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "flake8_cognitive_complexity-0.1.0.tar.gz", hash = "sha256:f202df054e4f6ff182b659c261922b9c684628a47beb19cb0973c50d6a7831c1"}, -] - -[package.dependencies] -cognitive_complexity = "*" -setuptools = "*" - -[[package]] -name = "flake8-expression-complexity" -version = "0.0.11" -description = "A flake8 extension that checks expressions complexity" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8_expression_complexity-0.0.11-py3-none-any.whl", hash = "sha256:b56bac37f7dd5d3d102a7111c89f6579c2cbd897b868147794c9ed12aadc627c"}, - {file = "flake8_expression_complexity-0.0.11.tar.gz", hash = "sha256:4dd8909fecbc20f53814cdcef9d0b04f61532764278d9b6e8026686812e96631"}, -] - -[package.dependencies] -astpretty = "*" -flake8 = "*" - -[[package]] -name = "flake8-functions" -version = "0.0.8" -description = "A flake8 extension that checks functions" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "flake8_functions-0.0.8-py3-none-any.whl", hash = "sha256:e1a88aa634d1aff6973f8c9dd64f30ab2beaac661e52eea96929ccc7ee7f64df"}, - {file = "flake8_functions-0.0.8.tar.gz", hash = "sha256:5446626673a9faecbf389fb411b90bdc87b002c387b72dc097b208e7a58f2a1c"}, -] - -[package.dependencies] -mr-proper = "*" -setuptools = "*" - -[[package]] -name = "flake8-import-order" -version = "0.18.2" -description = "Flake8 and pylama plugin that checks the ordering of import statements." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "flake8-import-order-0.18.2.tar.gz", hash = "sha256:e23941f892da3e0c09d711babbb0c73bc735242e9b216b726616758a920d900e"}, - {file = "flake8_import_order-0.18.2-py2.py3-none-any.whl", hash = "sha256:82ed59f1083b629b030ee9d3928d9e06b6213eb196fe745b3a7d4af2168130df"}, -] - -[package.dependencies] -pycodestyle = "*" -setuptools = "*" - -[[package]] -name = "flake8-polyfill" -version = "1.0.2" -description = "Polyfill package for Flake8 plugins" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, - {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, -] - -[package.dependencies] -flake8 = "*" - -[[package]] -name = "flake8-variables-names" -version = "0.0.6" -description = "A flake8 extension that helps to make more readable variables names" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8_variables_names-0.0.6-py3-none-any.whl", hash = "sha256:4aff935d54b3f7afcd026b4dae55029877bd05a7c507b294b45bc7bf577d7b47"}, - {file = "flake8_variables_names-0.0.6.tar.gz", hash = "sha256:292c50e4813d632aa3adcd02c185e7bb583f5fc8ebe02e70f13c958bfe46ad91"}, -] - [[package]] name = "ghp-import" version = "2.1.0" @@ -933,39 +682,6 @@ python-dateutil = ">=2.8.1" [package.extras] dev = ["flake8", "markdown", "twine", "wheel"] -[[package]] -name = "gitdb" -version = "4.0.11" -description = "Git Object Database" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, - {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, -] - -[package.dependencies] -smmap = ">=3.0.1,<6" - -[[package]] -name = "gitpython" -version = "3.1.40" -description = "GitPython is a Python library used to interact with Git repositories" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "GitPython-3.1.40-py3-none-any.whl", hash = "sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a"}, - {file = "GitPython-3.1.40.tar.gz", hash = "sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4"}, -] - -[package.dependencies] -gitdb = ">=4.0.1,<5" - -[package.extras] -test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-sugar"] - [[package]] name = "greenlet" version = "3.0.3" @@ -1040,14 +756,14 @@ test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.38.1" +version = "0.39.1" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "griffe-0.38.1-py3-none-any.whl", hash = "sha256:334c79d3b5964ade65c05dfcaf53518c576dedd387aaba5c9fd71212f34f1483"}, - {file = "griffe-0.38.1.tar.gz", hash = "sha256:bd68d7da7f3d87bc57eb9962b250db123efd9bbcc06c11c1a91b6e583b2a9361"}, + {file = "griffe-0.39.1-py3-none-any.whl", hash = "sha256:6ce4ecffcf0d2f96362c5974b3f7df812da8f8d4cfcc5ebc8202ef72656fc087"}, + {file = "griffe-0.39.1.tar.gz", hash = "sha256:ead8dfede6e6531cce6bf69090a4f3c6d36fdf923c43f8e85aa530552cef0c09"}, ] [package.dependencies] @@ -1172,14 +888,14 @@ files = [ [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.3" description = "A very fast and expressive template engine." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] [package.dependencies] @@ -1190,14 +906,14 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "markdown" -version = "3.5.1" +version = "3.5.2" description = "Python implementation of John Gruber's Markdown." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "Markdown-3.5.1-py3-none-any.whl", hash = "sha256:5874b47d4ee3f0b14d764324d2c94c03ea66bee56f2d929da9f2508d65e722dc"}, - {file = "Markdown-3.5.1.tar.gz", hash = "sha256:b65d7beb248dc22f2e8a31fb706d93798093c308dc1aba295aedeb9d41a813bd"}, + {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, + {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, ] [package.dependencies] @@ -1207,113 +923,74 @@ importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] -[[package]] -name = "markdown-it-py" -version = "3.0.0" -description = "Python port of markdown-it. Markdown parsing, done right!" -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, - {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, -] - -[package.dependencies] -mdurl = ">=0.1,<1.0" - -[package.extras] -benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] -profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.4" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, -] - -[[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -description = "Markdown URL utilities" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, - {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, + {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, ] [[package]] @@ -1486,37 +1163,20 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] [[package]] name = "mkdocstrings-python" -version = "1.7.5" +version = "1.8.0" description = "A Python handler for mkdocstrings." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocstrings_python-1.7.5-py3-none-any.whl", hash = "sha256:5f6246026353f0c0785135db70c3fe9a5d9318990fc7ceb11d62097b8ffdd704"}, - {file = "mkdocstrings_python-1.7.5.tar.gz", hash = "sha256:c7d143728257dbf1aa550446555a554b760dcd40a763f077189d298502b800be"}, + {file = "mkdocstrings_python-1.8.0-py3-none-any.whl", hash = "sha256:4209970cc90bec194568682a535848a8d8489516c6ed4adbe58bbc67b699ca9d"}, + {file = "mkdocstrings_python-1.8.0.tar.gz", hash = "sha256:1488bddf50ee42c07d9a488dddc197f8e8999c2899687043ec5dd1643d057192"}, ] [package.dependencies] griffe = ">=0.37" mkdocstrings = ">=0.20" -[[package]] -name = "mr-proper" -version = "0.0.7" -description = "Static Python code analyzer, that tries to check if functions in code are pure or not and why." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "mr_proper-0.0.7-py3-none-any.whl", hash = "sha256:74a1b60240c46f10ba518707ef72811a01e5c270da0a78b5dd2dd923d99fdb14"}, - {file = "mr_proper-0.0.7.tar.gz", hash = "sha256:03b517b19e617537f711ce418b125e5f2efd82ec881539cdee83195c78c14a02"}, -] - -[package.dependencies] -click = ">=7.1.2" -setuptools = "*" -stdlib-list = ">=0.5.0" - [[package]] name = "mypy" version = "0.982" @@ -1594,14 +1254,14 @@ files = [ [[package]] name = "nest-asyncio" -version = "1.5.8" +version = "1.6.0" description = "Patch asyncio to allow nested event loops" category = "dev" optional = false python-versions = ">=3.5" files = [ - {file = "nest_asyncio-1.5.8-py3-none-any.whl", hash = "sha256:accda7a339a70599cb08f9dd09a67e0c2ef8d8d6f4c07f96ab203f2ae254e48d"}, - {file = "nest_asyncio-1.5.8.tar.gz", hash = "sha256:25aa2ca0d2a5b5531956b9e273b45cf664cae2b145101d73b86b199978d48fdb"}, + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, ] [[package]] @@ -1621,62 +1281,62 @@ setuptools = "*" [[package]] name = "orjson" -version = "3.9.10" +version = "3.9.12" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "orjson-3.9.10-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c18a4da2f50050a03d1da5317388ef84a16013302a5281d6f64e4a3f406aabc4"}, - {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5148bab4d71f58948c7c39d12b14a9005b6ab35a0bdf317a8ade9a9e4d9d0bd5"}, - {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cf7837c3b11a2dfb589f8530b3cff2bd0307ace4c301e8997e95c7468c1378e"}, - {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c62b6fa2961a1dcc51ebe88771be5319a93fd89bd247c9ddf732bc250507bc2b"}, - {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb3922a7a804755bbe6b5be9b312e746137a03600f488290318936c1a2d4dc"}, - {file = "orjson-3.9.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1234dc92d011d3554d929b6cf058ac4a24d188d97be5e04355f1b9223e98bbe9"}, - {file = "orjson-3.9.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:06ad5543217e0e46fd7ab7ea45d506c76f878b87b1b4e369006bdb01acc05a83"}, - {file = "orjson-3.9.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4fd72fab7bddce46c6826994ce1e7de145ae1e9e106ebb8eb9ce1393ca01444d"}, - {file = "orjson-3.9.10-cp310-none-win32.whl", hash = "sha256:b5b7d4a44cc0e6ff98da5d56cde794385bdd212a86563ac321ca64d7f80c80d1"}, - {file = "orjson-3.9.10-cp310-none-win_amd64.whl", hash = "sha256:61804231099214e2f84998316f3238c4c2c4aaec302df12b21a64d72e2a135c7"}, - {file = "orjson-3.9.10-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cff7570d492bcf4b64cc862a6e2fb77edd5e5748ad715f487628f102815165e9"}, - {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8bc367f725dfc5cabeed1ae079d00369900231fbb5a5280cf0736c30e2adf7"}, - {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c812312847867b6335cfb264772f2a7e85b3b502d3a6b0586aa35e1858528ab1"}, - {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edd2856611e5050004f4722922b7b1cd6268da34102667bd49d2a2b18bafb81"}, - {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:674eb520f02422546c40401f4efaf8207b5e29e420c17051cddf6c02783ff5ca"}, - {file = "orjson-3.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0dc4310da8b5f6415949bd5ef937e60aeb0eb6b16f95041b5e43e6200821fb"}, - {file = "orjson-3.9.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e99c625b8c95d7741fe057585176b1b8783d46ed4b8932cf98ee145c4facf499"}, - {file = "orjson-3.9.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ec6f18f96b47299c11203edfbdc34e1b69085070d9a3d1f302810cc23ad36bf3"}, - {file = "orjson-3.9.10-cp311-none-win32.whl", hash = "sha256:ce0a29c28dfb8eccd0f16219360530bc3cfdf6bf70ca384dacd36e6c650ef8e8"}, - {file = "orjson-3.9.10-cp311-none-win_amd64.whl", hash = "sha256:cf80b550092cc480a0cbd0750e8189247ff45457e5a023305f7ef1bcec811616"}, - {file = "orjson-3.9.10-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:602a8001bdf60e1a7d544be29c82560a7b49319a0b31d62586548835bbe2c862"}, - {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f295efcd47b6124b01255d1491f9e46f17ef40d3d7eabf7364099e463fb45f0f"}, - {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92af0d00091e744587221e79f68d617b432425a7e59328ca4c496f774a356071"}, - {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5a02360e73e7208a872bf65a7554c9f15df5fe063dc047f79738998b0506a14"}, - {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:858379cbb08d84fe7583231077d9a36a1a20eb72f8c9076a45df8b083724ad1d"}, - {file = "orjson-3.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666c6fdcaac1f13eb982b649e1c311c08d7097cbda24f32612dae43648d8db8d"}, - {file = "orjson-3.9.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3fb205ab52a2e30354640780ce4587157a9563a68c9beaf52153e1cea9aa0921"}, - {file = "orjson-3.9.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7ec960b1b942ee3c69323b8721df2a3ce28ff40e7ca47873ae35bfafeb4555ca"}, - {file = "orjson-3.9.10-cp312-none-win_amd64.whl", hash = "sha256:3e892621434392199efb54e69edfff9f699f6cc36dd9553c5bf796058b14b20d"}, - {file = "orjson-3.9.10-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8b9ba0ccd5a7f4219e67fbbe25e6b4a46ceef783c42af7dbc1da548eb28b6531"}, - {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e2ecd1d349e62e3960695214f40939bbfdcaeaaa62ccc638f8e651cf0970e5f"}, - {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f433be3b3f4c66016d5a20e5b4444ef833a1f802ced13a2d852c637f69729c1"}, - {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4689270c35d4bb3102e103ac43c3f0b76b169760aff8bcf2d401a3e0e58cdb7f"}, - {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bd176f528a8151a6efc5359b853ba3cc0e82d4cd1fab9c1300c5d957dc8f48c"}, - {file = "orjson-3.9.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a2ce5ea4f71681623f04e2b7dadede3c7435dfb5e5e2d1d0ec25b35530e277b"}, - {file = "orjson-3.9.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:49f8ad582da6e8d2cf663c4ba5bf9f83cc052570a3a767487fec6af839b0e777"}, - {file = "orjson-3.9.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2a11b4b1a8415f105d989876a19b173f6cdc89ca13855ccc67c18efbd7cbd1f8"}, - {file = "orjson-3.9.10-cp38-none-win32.whl", hash = "sha256:a353bf1f565ed27ba71a419b2cd3db9d6151da426b61b289b6ba1422a702e643"}, - {file = "orjson-3.9.10-cp38-none-win_amd64.whl", hash = "sha256:e28a50b5be854e18d54f75ef1bb13e1abf4bc650ab9d635e4258c58e71eb6ad5"}, - {file = "orjson-3.9.10-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ee5926746232f627a3be1cc175b2cfad24d0170d520361f4ce3fa2fd83f09e1d"}, - {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a73160e823151f33cdc05fe2cea557c5ef12fdf276ce29bb4f1c571c8368a60"}, - {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c338ed69ad0b8f8f8920c13f529889fe0771abbb46550013e3c3d01e5174deef"}, - {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5869e8e130e99687d9e4be835116c4ebd83ca92e52e55810962446d841aba8de"}, - {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2c1e559d96a7f94a4f581e2a32d6d610df5840881a8cba8f25e446f4d792df3"}, - {file = "orjson-3.9.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a3a3a72c9811b56adf8bcc829b010163bb2fc308877e50e9910c9357e78521"}, - {file = "orjson-3.9.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7f8fb7f5ecf4f6355683ac6881fd64b5bb2b8a60e3ccde6ff799e48791d8f864"}, - {file = "orjson-3.9.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c943b35ecdf7123b2d81d225397efddf0bce2e81db2f3ae633ead38e85cd5ade"}, - {file = "orjson-3.9.10-cp39-none-win32.whl", hash = "sha256:fb0b361d73f6b8eeceba47cd37070b5e6c9de5beaeaa63a1cb35c7e1a73ef088"}, - {file = "orjson-3.9.10-cp39-none-win_amd64.whl", hash = "sha256:b90f340cb6397ec7a854157fac03f0c82b744abdd1c0941a024c3c29d1340aff"}, - {file = "orjson-3.9.10.tar.gz", hash = "sha256:9ebbdbd6a046c304b1845e96fbcc5559cd296b4dfd3ad2509e33c4d9ce07d6a1"}, + {file = "orjson-3.9.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6b4e2bed7d00753c438e83b613923afdd067564ff7ed696bfe3a7b073a236e07"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd1b8ec63f0bf54a50b498eedeccdca23bd7b658f81c524d18e410c203189365"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab8add018a53665042a5ae68200f1ad14c7953fa12110d12d41166f111724656"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12756a108875526b76e505afe6d6ba34960ac6b8c5ec2f35faf73ef161e97e07"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:890e7519c0c70296253660455f77e3a194554a3c45e42aa193cdebc76a02d82b"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d664880d7f016efbae97c725b243b33c2cbb4851ddc77f683fd1eec4a7894146"}, + {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cfdaede0fa5b500314ec7b1249c7e30e871504a57004acd116be6acdda3b8ab3"}, + {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6492ff5953011e1ba9ed1bf086835fd574bd0a3cbe252db8e15ed72a30479081"}, + {file = "orjson-3.9.12-cp310-none-win32.whl", hash = "sha256:29bf08e2eadb2c480fdc2e2daae58f2f013dff5d3b506edd1e02963b9ce9f8a9"}, + {file = "orjson-3.9.12-cp310-none-win_amd64.whl", hash = "sha256:0fc156fba60d6b50743337ba09f052d8afc8b64595112996d22f5fce01ab57da"}, + {file = "orjson-3.9.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2849f88a0a12b8d94579b67486cbd8f3a49e36a4cb3d3f0ab352c596078c730c"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3186b18754befa660b31c649a108a915493ea69b4fc33f624ed854ad3563ac65"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbbf313c9fb9d4f6cf9c22ced4b6682230457741daeb3d7060c5d06c2e73884a"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e8cd005b3926c3db9b63d264bd05e1bf4451787cc79a048f27f5190a9a0311"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59feb148392d9155f3bfed0a2a3209268e000c2c3c834fb8fe1a6af9392efcbf"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4ae815a172a1f073b05b9e04273e3b23e608a0858c4e76f606d2d75fcabde0c"}, + {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed398f9a9d5a1bf55b6e362ffc80ac846af2122d14a8243a1e6510a4eabcb71e"}, + {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d3cfb76600c5a1e6be91326b8f3b83035a370e727854a96d801c1ea08b708073"}, + {file = "orjson-3.9.12-cp311-none-win32.whl", hash = "sha256:a2b6f5252c92bcab3b742ddb3ac195c0fa74bed4319acd74f5d54d79ef4715dc"}, + {file = "orjson-3.9.12-cp311-none-win_amd64.whl", hash = "sha256:c95488e4aa1d078ff5776b58f66bd29d628fa59adcb2047f4efd3ecb2bd41a71"}, + {file = "orjson-3.9.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d6ce2062c4af43b92b0221ed4f445632c6bf4213f8a7da5396a122931377acd9"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:950951799967558c214cd6cceb7ceceed6f81d2c3c4135ee4a2c9c69f58aa225"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2dfaf71499d6fd4153f5c86eebb68e3ec1bf95851b030a4b55c7637a37bbdee4"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:659a8d7279e46c97661839035a1a218b61957316bf0202674e944ac5cfe7ed83"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af17fa87bccad0b7f6fd8ac8f9cbc9ee656b4552783b10b97a071337616db3e4"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd52dec9eddf4c8c74392f3fd52fa137b5f2e2bed1d9ae958d879de5f7d7cded"}, + {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:640e2b5d8e36b970202cfd0799d11a9a4ab46cf9212332cd642101ec952df7c8"}, + {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:daa438bd8024e03bcea2c5a92cd719a663a58e223fba967296b6ab9992259dbf"}, + {file = "orjson-3.9.12-cp312-none-win_amd64.whl", hash = "sha256:1bb8f657c39ecdb924d02e809f992c9aafeb1ad70127d53fb573a6a6ab59d549"}, + {file = "orjson-3.9.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f4098c7674901402c86ba6045a551a2ee345f9f7ed54eeffc7d86d155c8427e5"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5586a533998267458fad3a457d6f3cdbddbcce696c916599fa8e2a10a89b24d3"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54071b7398cd3f90e4bb61df46705ee96cb5e33e53fc0b2f47dbd9b000e238e1"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:67426651faa671b40443ea6f03065f9c8e22272b62fa23238b3efdacd301df31"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4a0cd56e8ee56b203abae7d482ac0d233dbfb436bb2e2d5cbcb539fe1200a312"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a84a0c3d4841a42e2571b1c1ead20a83e2792644c5827a606c50fc8af7ca4bee"}, + {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:09d60450cda3fa6c8ed17770c3a88473a16460cd0ff2ba74ef0df663b6fd3bb8"}, + {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bc82a4db9934a78ade211cf2e07161e4f068a461c1796465d10069cb50b32a80"}, + {file = "orjson-3.9.12-cp38-none-win32.whl", hash = "sha256:61563d5d3b0019804d782137a4f32c72dc44c84e7d078b89d2d2a1adbaa47b52"}, + {file = "orjson-3.9.12-cp38-none-win_amd64.whl", hash = "sha256:410f24309fbbaa2fab776e3212a81b96a1ec6037259359a32ea79fbccfcf76aa"}, + {file = "orjson-3.9.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e773f251258dd82795fd5daeac081d00b97bacf1548e44e71245543374874bcf"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b159baecfda51c840a619948c25817d37733a4d9877fea96590ef8606468b362"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:975e72e81a249174840d5a8df977d067b0183ef1560a32998be340f7e195c730"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06e42e899dde61eb1851a9fad7f1a21b8e4be063438399b63c07839b57668f6c"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c157e999e5694475a5515942aebeed6e43f7a1ed52267c1c93dcfde7d78d421"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dde1bc7c035f2d03aa49dc8642d9c6c9b1a81f2470e02055e76ed8853cfae0c3"}, + {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b0e9d73cdbdad76a53a48f563447e0e1ce34bcecef4614eb4b146383e6e7d8c9"}, + {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96e44b21fe407b8ed48afbb3721f3c8c8ce17e345fbe232bd4651ace7317782d"}, + {file = "orjson-3.9.12-cp39-none-win32.whl", hash = "sha256:cbd0f3555205bf2a60f8812133f2452d498dbefa14423ba90fe89f32276f7abf"}, + {file = "orjson-3.9.12-cp39-none-win_amd64.whl", hash = "sha256:03ea7ee7e992532c2f4a06edd7ee1553f0644790553a118e003e3c405add41fa"}, + {file = "orjson-3.9.12.tar.gz", hash = "sha256:da908d23a3b3243632b523344403b128722a5f45e278a8343c2bb67538dff0e4"}, ] [[package]] @@ -1703,18 +1363,6 @@ files = [ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] -[[package]] -name = "pbr" -version = "6.0.0" -description = "Python Build Reasonableness" -category = "dev" -optional = false -python-versions = ">=2.6" -files = [ - {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"}, - {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"}, -] - [[package]] name = "platformdirs" version = "4.1.0" @@ -1733,14 +1381,14 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -1860,18 +1508,6 @@ files = [ {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, ] -[[package]] -name = "pycodestyle" -version = "2.7.0" -description = "Python style guide checker" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, - {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, -] - [[package]] name = "pycparser" version = "2.21" @@ -2022,18 +1658,6 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" -[[package]] -name = "pyflakes" -version = "2.3.1" -description = "passive checker of Python programs" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, - {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, -] - [[package]] name = "pygments" version = "2.17.2" @@ -2052,14 +1676,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.6" +version = "10.7" description = "Extension pack for Python Markdown." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.6-py3-none-any.whl", hash = "sha256:561eb3a5f3c3c2512952a4d6f5b311aa124b7147bd54a3ea0f36ce030c7e3dd9"}, - {file = "pymdown_extensions-10.6.tar.gz", hash = "sha256:e4531379e0d74b329ff264217ef5b8b1a37bed3afe36f98001b74ecff52215c0"}, + {file = "pymdown_extensions-10.7-py3-none-any.whl", hash = "sha256:6ca215bc57bc12bf32b414887a68b810637d039124ed9b2e5bd3325cbb2c050c"}, + {file = "pymdown_extensions-10.7.tar.gz", hash = "sha256:c0d64d5cf62566f59e6b2b690a4095c931107c250a8c8e1351c1de5f6b036deb"}, ] [package.dependencies] @@ -2087,14 +1711,14 @@ rsa = ["cryptography"] [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -2373,25 +1997,32 @@ socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] -name = "rich" -version = "13.7.0" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +name = "ruff" +version = "0.0.275" +description = "An extremely fast Python linter, written in Rust." category = "dev" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.7" files = [ - {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, - {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, + {file = "ruff-0.0.275-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:5e6554a072e7ce81eb6f0bec1cebd3dcb0e358652c0f4900d7d630d61691e914"}, + {file = "ruff-0.0.275-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1cc599022fe5ffb143a965b8d659eb64161ab8ab4433d208777eab018a1aab67"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5206fc1cd8c1c1deadd2e6360c0dbcd690f1c845da588ca9d32e4a764a402c60"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c4e6468da26f77b90cae35319d310999f471a8c352998e9b39937a23750149e"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0dbdea02942131dbc15dd45f431d152224f15e1dd1859fcd0c0487b658f60f1a"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:22efd9f41af27ef8fb9779462c46c35c89134d33e326c889971e10b2eaf50c63"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c09662112cfa22d7467a19252a546291fd0eae4f423e52b75a7a2000a1894db"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80043726662144876a381efaab88841c88e8df8baa69559f96b22d4fa216bef1"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5859ee543b01b7eb67835dfd505faa8bb7cc1550f0295c92c1401b45b42be399"}, + {file = "ruff-0.0.275-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c8ace4d40a57b5ea3c16555f25a6b16bc5d8b2779ae1912ce2633543d4e9b1da"}, + {file = "ruff-0.0.275-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8347fc16aa185aae275906c4ac5b770e00c896b6a0acd5ba521f158801911998"}, + {file = "ruff-0.0.275-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ec43658c64bfda44fd84bbea9da8c7a3b34f65448192d1c4dd63e9f4e7abfdd4"}, + {file = "ruff-0.0.275-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:508b13f7ca37274cceaba4fb3ea5da6ca192356323d92acf39462337c33ad14e"}, + {file = "ruff-0.0.275-py3-none-win32.whl", hash = "sha256:6afb1c4422f24f361e877937e2a44b3f8176774a476f5e33845ebfe887dd5ec2"}, + {file = "ruff-0.0.275-py3-none-win_amd64.whl", hash = "sha256:d9b264d78621bf7b698b6755d4913ab52c19bd28bee1a16001f954d64c1a1220"}, + {file = "ruff-0.0.275-py3-none-win_arm64.whl", hash = "sha256:a19ce3bea71023eee5f0f089dde4a4272d088d5ac0b675867e074983238ccc65"}, + {file = "ruff-0.0.275.tar.gz", hash = "sha256:a63a0b645da699ae5c758fce19188e901b3033ec54d862d93fcd042addf7f38d"}, ] -[package.dependencies] -markdown-it-py = ">=2.2.0" -pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<9)"] - [[package]] name = "setuptools" version = "69.0.3" @@ -2421,18 +2052,6 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -[[package]] -name = "smmap" -version = "5.0.1" -description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, - {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, -] - [[package]] name = "sniffio" version = "1.3.0" @@ -2522,14 +2141,14 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "starlette" -version = "0.32.0.post1" +version = "0.35.1" description = "The little ASGI library that shines." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "starlette-0.32.0.post1-py3-none-any.whl", hash = "sha256:cd0cb10ddb49313f609cedfac62c8c12e56c7314b66d89bb077ba228bada1b09"}, - {file = "starlette-0.32.0.post1.tar.gz", hash = "sha256:e54e2b7e2fb06dff9eac40133583f10dfa05913f5a85bf26f427c7a40a9a3d02"}, + {file = "starlette-0.35.1-py3-none-any.whl", hash = "sha256:50bbbda9baa098e361f398fda0928062abbaf1f54f4fadcbe17c092a01eb9a25"}, + {file = "starlette-0.35.1.tar.gz", hash = "sha256:3e2639dac3520e4f58734ed22553f950d3f3cb1001cd2eaac4d57e8cdc5f66bc"}, ] [package.dependencies] @@ -2539,40 +2158,6 @@ typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\"" [package.extras] full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] -[[package]] -name = "stdlib-list" -version = "0.10.0" -description = "A list of Python Standard Libraries (2.7 through 3.12)." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "stdlib_list-0.10.0-py3-none-any.whl", hash = "sha256:b3a911bc441d03e0332dd1a9e7d0870ba3bb0a542a74d7524f54fb431256e214"}, - {file = "stdlib_list-0.10.0.tar.gz", hash = "sha256:6519c50d645513ed287657bfe856d527f277331540691ddeaf77b25459964a14"}, -] - -[package.extras] -dev = ["build", "stdlib-list[doc,lint,test]"] -doc = ["furo", "sphinx"] -lint = ["black", "mypy", "ruff"] -support = ["sphobjinv"] -test = ["coverage[toml]", "pytest", "pytest-cov"] - -[[package]] -name = "stevedore" -version = "5.1.0" -description = "Manage dynamic plugins for Python applications" -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, - {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, -] - -[package.dependencies] -pbr = ">=2.0.0,<2.1.0 || >2.1.0" - [[package]] name = "tomli" version = "2.0.1" @@ -2587,14 +2172,14 @@ files = [ [[package]] name = "types-aiofiles" -version = "23.2.0.0" +version = "23.2.0.20240106" description = "Typing stubs for aiofiles" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-aiofiles-23.2.0.0.tar.gz", hash = "sha256:b6a7127bd232e0802532837b84140b1cd5df19ee60bea3a5699720d2b583361b"}, - {file = "types_aiofiles-23.2.0.0-py3-none-any.whl", hash = "sha256:5d6719e8148cb2a9c4ea46dad86d50d3b675c46a940adca698533a8d2216d53d"}, + {file = "types-aiofiles-23.2.0.20240106.tar.gz", hash = "sha256:ef4fa3072441c58beaadbd0d07ba18e89beff49c71648dd223e2ca861f3dac53"}, + {file = "types_aiofiles-23.2.0.20240106-py3-none-any.whl", hash = "sha256:7324f9a9f7200c1f4986a9e40a42b548290f707b967709f30b280e99fdacbd99"}, ] [[package]] @@ -2671,14 +2256,14 @@ files = [ [[package]] name = "types-requests" -version = "2.31.0.10" +version = "2.31.0.20240125" description = "Typing stubs for requests" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "types-requests-2.31.0.10.tar.gz", hash = "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92"}, - {file = "types_requests-2.31.0.10-py3-none-any.whl", hash = "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc"}, + {file = "types-requests-2.31.0.20240125.tar.gz", hash = "sha256:03a28ce1d7cd54199148e043b2079cdded22d6795d19a2c2a6791a4b2b5e2eb5"}, + {file = "types_requests-2.31.0.20240125-py3-none-any.whl", hash = "sha256:9592a9a4cb92d6d75d9b491a41477272b710e021011a2a3061157e2fb1f1a5d1"}, ] [package.dependencies] @@ -2890,4 +2475,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "6b8390a5776272f4be085bc41b7f2414adcec077684273f983e9bbdf12f6a784" +content-hash = "93d791c31977d250ff40bed40a7b9e48656d1543e0c06188c27ae782a1b3fb27" diff --git a/pyproject.toml b/pyproject.toml index 6cd17d9a0..970b9447b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,16 +77,9 @@ pytest-cov = "^4.0.0" codecov = "^2.1.13" pytest-asyncio = "^0.21.0" fastapi = ">=0.105.0" -flake8 = "^3.9.2" -flake8-black = "^0.3.6" -flake8-bugbear = "^23.3.12" -flake8-import-order = "^0.18.1" -flake8-bandit = "^3.0.0" -flake8-builtins = "^2.1.0" -flake8-variables-names = "^0.0.6" -flake8-cognitive-complexity = "^0.1.0" -flake8-functions = "^0.0.8" -flake8-expression-complexity = "^0.0.11" + +black = "^23.1.0" +ruff = "^0.0.275" # types mypy = "^0.982" @@ -170,3 +163,9 @@ ignore_missing_imports = true based_on_style = "pep8" disable_ending_comma_heuristic = true split_arguments_when_comma_terminated = true + +[tool.ruff] +select = ["E", "F", "I"] +ignore = ["E402"] +line-length = 120 +src = ["ormar", "tests"] From 87ecdbc4f86217398c6b10859f185890fc62fbe3 Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 25 Jan 2024 15:18:59 +0100 Subject: [PATCH 25/95] reforat with ruff, fix jobs --- .flake8 | 6 - .github/workflows/lint.yml | 2 +- .github/workflows/type-check.yml | 2 +- Makefile | 8 +- benchmarks/conftest.py | 4 +- docs_src/aggregations/docs001.py | 4 +- docs_src/fastapi/docs001.py | 3 +- docs_src/fastapi/mypy/docs001.py | 3 +- docs_src/fields/docs001.py | 3 +- docs_src/fields/docs002.py | 7 +- docs_src/fields/docs003.py | 3 +- docs_src/fields/docs004.py | 3 +- docs_src/models/docs001.py | 3 +- docs_src/models/docs002.py | 3 +- docs_src/models/docs003.py | 3 +- docs_src/models/docs004.py | 7 +- docs_src/models/docs005.py | 3 +- docs_src/models/docs006.py | 3 +- docs_src/models/docs007.py | 3 +- docs_src/models/docs008.py | 3 +- docs_src/models/docs009.py | 2 +- docs_src/models/docs010.py | 2 +- docs_src/models/docs011.py | 6 +- docs_src/models/docs012.py | 3 +- docs_src/models/docs013.py | 3 +- docs_src/models/docs014.py | 3 +- docs_src/models/docs015.py | 3 +- docs_src/models/docs016.py | 3 +- docs_src/models/docs017.py | 3 +- docs_src/models/docs018.py | 4 +- docs_src/queries/docs002.py | 17 ++- docs_src/queries/docs003.py | 19 ++- docs_src/queries/docs005.py | 17 ++- docs_src/queries/docs006.py | 34 +++-- docs_src/queries/docs007.py | 3 +- docs_src/queries/docs008.py | 63 ++++++--- docs_src/queries/docs009.py | 40 +++--- docs_src/relations/docs001.py | 5 +- docs_src/relations/docs002.py | 2 +- examples/fastapi_quick_start.py | 3 +- examples/script_from_readme.py | 3 +- ormar/__init__.py | 23 ++-- ormar/decorators/signals.py | 2 +- ormar/fields/__init__.py | 8 +- ormar/fields/base.py | 5 +- ormar/fields/constraints.py | 2 +- ormar/fields/foreign_key.py | 8 +- ormar/fields/many_to_many.py | 5 +- ormar/fields/model_fields.py | 7 +- ormar/fields/parsers.py | 2 +- ormar/fields/sqlalchemy_encrypted.py | 2 +- ormar/fields/through_field.py | 5 +- ormar/models/descriptors/descriptors.py | 6 +- ormar/models/excludable.py | 2 +- ormar/models/helpers/__init__.py | 4 +- ormar/models/helpers/models.py | 6 +- ormar/models/helpers/pydantic.py | 6 +- .../helpers/related_names_validation.py | 3 +- ormar/models/helpers/relations.py | 27 ++-- ormar/models/helpers/sqlalchemy.py | 5 +- ormar/models/helpers/validation.py | 15 ++- ormar/models/metaclass.py | 53 +++++--- ormar/models/mixins/alias_mixin.py | 2 +- ormar/models/mixins/excludable_mixin.py | 2 +- ormar/models/mixins/merge_mixin.py | 2 +- ormar/models/mixins/prefetch_mixin.py | 6 +- ormar/models/mixins/pydantic_mixin.py | 5 +- ormar/models/mixins/relation_mixin.py | 2 +- ormar/models/mixins/save_mixin.py | 2 +- ormar/models/model.py | 2 +- ormar/models/model_row.py | 2 +- ormar/models/newbasemodel.py | 7 +- ormar/models/ormar_config.py | 6 +- ormar/models/traversible.py | 2 +- ormar/protocols/queryset_protocol.py | 2 +- ormar/queryset/__init__.py | 5 +- ormar/queryset/actions/filter_action.py | 2 +- ormar/queryset/actions/query_action.py | 2 +- ormar/queryset/actions/select_action.py | 2 +- ormar/queryset/clause.py | 3 +- ormar/queryset/field_accessor.py | 2 +- ormar/queryset/join.py | 6 +- ormar/queryset/queries/filter_query.py | 1 + ormar/queryset/queries/prefetch_query.py | 19 +-- ormar/queryset/queries/query.py | 6 +- ormar/queryset/queryset.py | 6 +- ormar/queryset/reverse_alias_resolver.py | 6 +- ormar/queryset/utils.py | 4 +- ormar/relations/alias_manager.py | 4 +- ormar/relations/querysetproxy.py | 11 +- ormar/relations/relation.py | 4 +- ormar/relations/relation_manager.py | 6 +- ormar/relations/relation_proxy.py | 5 +- ormar/signals/signal.py | 2 +- pyproject.toml | 2 +- .../test_deferred/test_forward_cross_refs.py | 17 ++- tests/test_deferred/test_forward_refs.py | 48 ++++--- .../test_more_same_table_joins.py | 33 +++-- tests/test_deferred/test_same_table_joins.py | 33 +++-- .../test_encryption/test_encrypted_columns.py | 10 +- .../test_complex_relation_tree_performance.py | 40 ++++-- .../test_dumping_model_to_dict.py | 2 +- .../test_excludable_items.py | 12 +- .../test_excluding_fields_in_fastapi.py | 22 +++- .../test_excluding_fields_with_default.py | 6 +- .../test_excluding_subset_of_columns.py | 14 +- .../test_pydantic_dict_params.py | 6 +- tests/test_fastapi/test_binary_fields.py | 4 +- ...est_docs_with_multiple_relations_to_one.py | 10 +- tests/test_fastapi/test_enum_schema.py | 2 +- .../test_excludes_with_get_pydantic.py | 16 +-- tests/test_fastapi/test_excluding_fields.py | 14 +- .../test_extra_ignore_parameter.py | 12 +- tests/test_fastapi/test_fastapi_docs.py | 18 ++- tests/test_fastapi/test_fastapi_usage.py | 14 +- .../test_inheritance_concrete_fastapi.py | 10 +- .../test_inheritance_mixins_fastapi.py | 9 +- tests/test_fastapi/test_json_field_fastapi.py | 7 +- tests/test_fastapi/test_m2m_forwardref.py | 14 +- .../test_more_reallife_fastapi.py | 14 +- tests/test_fastapi/test_nested_saving.py | 17 ++- tests/test_fastapi/test_recursion_error.py | 21 ++- .../test_relations_with_nested_defaults.py | 56 +++++--- .../test_schema_not_allowed_params.py | 6 +- .../test_fastapi/test_skip_reverse_models.py | 9 +- tests/test_fastapi/test_wekref_exclusion.py | 6 +- ...est_excluding_parent_fields_inheritance.py | 34 +++-- .../test_geting_pydantic_models.py | 6 +- .../test_inheritance_concrete.py | 121 +++++++++++++----- .../test_inheritance_mixins.py | 72 +++++++---- .../test_inheritance_of_property_fields.py | 13 +- .../test_inheritance_with_default.py | 2 +- ...erited_class_is_not_abstract_by_default.py | 12 +- .../test_nested_models_pydantic.py | 2 +- .../test_pydantic_fields_order.py | 6 +- .../test_validators_are_inherited.py | 2 +- .../test_validators_in_generated_pydantic.py | 3 +- .../test_check_constraints.py | 13 +- .../test_index_constraints.py | 13 +- .../test_unique_constraints.py | 10 +- .../pks_and_fks/test_non_integer_pkey.py | 2 +- .../pks_and_fks/test_saving_string_pks.py | 4 +- .../pks_and_fks/test_uuid_fks.py | 14 +- tests/test_model_definition/test_aliases.py | 4 +- tests/test_model_definition/test_columns.py | 4 +- .../test_create_uses_init_for_consistency.py | 4 +- .../test_dates_with_timezone.py | 5 +- .../test_equality_and_hash.py | 2 +- .../test_extra_ignore_parameter.py | 4 +- .../test_fields_access.py | 5 +- ...oreign_key_value_used_for_related_model.py | 4 +- tests/test_model_definition/test_iterate.py | 5 +- .../test_model_construct.py | 4 +- .../test_model_definition.py | 8 +- tests/test_model_definition/test_models.py | 7 +- .../test_models_are_pickable.py | 2 +- .../test_overwriting_pydantic_field_type.py | 2 +- .../test_overwriting_sql_nullable.py | 5 +- .../test_pk_field_is_always_not_null.py | 2 +- .../test_model_definition/test_properties.py | 3 +- .../test_pydantic_fields.py | 2 +- .../test_pydantic_only_fields.py | 2 +- .../test_pydantic_private_attributes.py | 2 +- .../test_model_definition/test_save_status.py | 4 +- .../test_saving_nullable_fields.py | 5 +- .../test_server_default.py | 3 +- .../test_setting_comments_in_db.py | 4 +- .../test_excludes_in_load_all.py | 18 ++- tests/test_model_methods/test_load_all.py | 12 +- .../test_populate_default_values.py | 3 +- tests/test_model_methods/test_save_related.py | 10 +- .../test_save_related_from_dict.py | 6 +- .../test_save_related_uuid.py | 6 +- tests/test_model_methods/test_update.py | 10 +- tests/test_model_methods/test_upsert.py | 12 +- .../test_ordering/test_default_model_order.py | 22 +++- .../test_default_relation_order.py | 23 +++- .../test_default_through_relation_order.py | 54 +++++--- .../test_proper_order_of_sorting_apply.py | 10 +- tests/test_queries/test_adding_related.py | 12 +- tests/test_queries/test_aggr_functions.py | 15 +-- .../test_deep_relations_select_all.py | 64 ++++----- tests/test_queries/test_filter_groups.py | 7 +- .../test_indirect_relations_to_self.py | 14 +- tests/test_queries/test_isnull_filter.py | 15 +-- .../test_nested_reverse_relations.py | 11 +- .../test_non_relation_fields_not_merged.py | 9 +- tests/test_queries/test_or_filters.py | 27 +++- tests/test_queries/test_order_by.py | 50 ++++---- tests/test_queries/test_pagination.py | 4 +- .../test_queryproxy_on_m2m_models.py | 35 +++-- .../test_queryset_level_methods.py | 52 ++++---- ...t_quoting_table_names_in_on_join_clause.py | 20 +-- .../test_reserved_sql_keywords_escaped.py | 8 +- .../test_queries/test_reverse_fk_queryset.py | 22 ++-- .../test_selecting_subset_of_columns.py | 34 ++--- .../test_values_and_values_list.py | 6 +- tests/test_relations/test_cascades.py | 2 +- ...ustomizing_through_model_relation_names.py | 12 +- .../test_database_fk_creation.py | 8 +- tests/test_relations/test_foreign_keys.py | 40 +++--- .../test_relations/test_m2m_through_fields.py | 14 +- tests/test_relations/test_many_to_many.py | 8 +- ...est_postgress_select_related_with_limit.py | 24 ++-- tests/test_relations/test_prefetch_related.py | 50 ++++---- ...efetch_related_multiple_models_relation.py | 23 ++-- .../test_python_style_relations.py | 20 +-- .../test_relations_default_exception.py | 28 ++-- tests/test_relations/test_saving_related.py | 16 +-- .../test_select_related_with_limit.py | 29 ++--- ...select_related_with_m2m_and_pk_name_set.py | 8 +- .../test_selecting_proper_table_prefix.py | 20 +-- tests/test_relations/test_skipping_reverse.py | 4 +- .../test_through_relations_fail.py | 13 +- tests/test_relations/test_weakref_checking.py | 20 ++- tests/test_signals/test_signals.py | 24 ++-- .../test_signals_for_relations.py | 30 ++--- tests/test_types.py | 19 +-- tests/test_utils/test_queryset_utils.py | 12 +- 219 files changed, 1399 insertions(+), 1189 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 59b600982..000000000 --- a/.flake8 +++ /dev/null @@ -1,6 +0,0 @@ -[flake8] -ignore = ANN101, ANN102, W503, S101, CFQ004, S311 -max-complexity = 8 -max-line-length = 88 -import-order-style = pycharm -exclude = p38venv,.pytest_cache diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 94455542f..327d9ff32 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,4 +28,4 @@ jobs: env: POETRY_VIRTUALENVS_CREATE: false - name: Lint - run: make style + run: python -m ruff . --fix diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml index c8d3084fe..13ef05170 100644 --- a/.github/workflows/type-check.yml +++ b/.github/workflows/type-check.yml @@ -28,4 +28,4 @@ jobs: env: POETRY_VIRTUALENVS_CREATE: false - name: Lint - run: make type_check + run: python -m mypy . --ignore-missing-imports --install-types --non-interactive diff --git a/Makefile b/Makefile index 2bf7b9301..2d80d56af 100644 --- a/Makefile +++ b/Makefile @@ -21,14 +21,8 @@ test: coverage: pytest --cov=ormar --cov=tests --cov-fail-under=100 --cov-report=term-missing - -fmt: - poetry run python -m black --line-length=120 . - type_check: mkdir -p .mypy_cache && poetry run python -m mypy . --ignore-missing-imports --install-types --non-interactive lint: - poetry run python -m ruff . --fix - -style: fmt lint \ No newline at end of file + poetry run python -m ruff . --fix \ No newline at end of file diff --git a/benchmarks/conftest.py b/benchmarks/conftest.py index e14e65da3..2795db52d 100644 --- a/benchmarks/conftest.py +++ b/benchmarks/conftest.py @@ -5,11 +5,10 @@ import databases import nest_asyncio +import ormar import pytest import pytest_asyncio import sqlalchemy - -import ormar from tests.settings import DATABASE_URL nest_asyncio.apply() @@ -25,6 +24,7 @@ database=database, ) + class Author(ormar.Model): class Meta(BaseMeta): tablename = "authors" diff --git a/docs_src/aggregations/docs001.py b/docs_src/aggregations/docs001.py index 843e010b6..36f81447c 100644 --- a/docs_src/aggregations/docs001.py +++ b/docs_src/aggregations/docs001.py @@ -1,9 +1,8 @@ from typing import Optional import databases -import sqlalchemy - import ormar +import sqlalchemy from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -15,6 +14,7 @@ database=database, ) + class Author(ormar.Model): class Meta(BaseMeta): tablename = "authors" diff --git a/docs_src/fastapi/docs001.py b/docs_src/fastapi/docs001.py index 4d2087c74..fc38cef13 100644 --- a/docs_src/fastapi/docs001.py +++ b/docs_src/fastapi/docs001.py @@ -1,11 +1,10 @@ from typing import List, Optional import databases +import ormar import sqlalchemy from fastapi import FastAPI -import ormar - app = FastAPI() metadata = sqlalchemy.MetaData() database = databases.Database("sqlite:///test.db") diff --git a/docs_src/fastapi/mypy/docs001.py b/docs_src/fastapi/mypy/docs001.py index 2c74a7707..ddc0d5b9d 100644 --- a/docs_src/fastapi/mypy/docs001.py +++ b/docs_src/fastapi/mypy/docs001.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/fields/docs001.py b/docs_src/fields/docs001.py index d1c9144c5..ad67cf1e6 100644 --- a/docs_src/fields/docs001.py +++ b/docs_src/fields/docs001.py @@ -1,9 +1,8 @@ from typing import Optional import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/fields/docs002.py b/docs_src/fields/docs002.py index 243285610..f9ac2394d 100644 --- a/docs_src/fields/docs002.py +++ b/docs_src/fields/docs002.py @@ -1,9 +1,8 @@ from typing import Optional import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() @@ -26,7 +25,9 @@ class Meta: id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) completed: bool = ormar.Boolean(default=False) - department: Optional[Department] = ormar.ForeignKey(Department, related_name="my_courses") + department: Optional[Department] = ormar.ForeignKey( + Department, related_name="my_courses" + ) department = Department(name="Science") diff --git a/docs_src/fields/docs003.py b/docs_src/fields/docs003.py index 5066f60df..8390a649c 100644 --- a/docs_src/fields/docs003.py +++ b/docs_src/fields/docs003.py @@ -1,9 +1,8 @@ from typing import Optional import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/fields/docs004.py b/docs_src/fields/docs004.py index 8a4e1ab1d..0d155af3a 100644 --- a/docs_src/fields/docs004.py +++ b/docs_src/fields/docs004.py @@ -1,11 +1,10 @@ from datetime import datetime import databases +import ormar import sqlalchemy from sqlalchemy import func, text -import ormar - database = databases.Database("sqlite:///test.db") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs001.py b/docs_src/models/docs001.py index 36d7fd921..2d3fe1fd8 100644 --- a/docs_src/models/docs001.py +++ b/docs_src/models/docs001.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs002.py b/docs_src/models/docs002.py index 3450dae71..995a960b7 100644 --- a/docs_src/models/docs002.py +++ b/docs_src/models/docs002.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs003.py b/docs_src/models/docs003.py index 38b4763ad..917fd73ea 100644 --- a/docs_src/models/docs003.py +++ b/docs_src/models/docs003.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs004.py b/docs_src/models/docs004.py index 0cac672be..3a4eac4a5 100644 --- a/docs_src/models/docs004.py +++ b/docs_src/models/docs004.py @@ -1,14 +1,15 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() class Course(ormar.Model): - class Meta(ormar.ModelMeta): # note you don't have to subclass - but it's recommended for ide completion and mypy + class Meta( + ormar.ModelMeta + ): # note you don't have to subclass - but it's recommended for ide completion and mypy database = database metadata = metadata diff --git a/docs_src/models/docs005.py b/docs_src/models/docs005.py index 5190ea3f1..2cc2b5f87 100644 --- a/docs_src/models/docs005.py +++ b/docs_src/models/docs005.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs006.py b/docs_src/models/docs006.py index 7649c2c93..b9b24eef7 100644 --- a/docs_src/models/docs006.py +++ b/docs_src/models/docs006.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs007.py b/docs_src/models/docs007.py index 9dfe28a46..6e2bcda98 100644 --- a/docs_src/models/docs007.py +++ b/docs_src/models/docs007.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs008.py b/docs_src/models/docs008.py index da2444c64..faaafc7a2 100644 --- a/docs_src/models/docs008.py +++ b/docs_src/models/docs008.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///test.db", force_rollback=True) metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs009.py b/docs_src/models/docs009.py index 747f612d9..328e315e4 100644 --- a/docs_src/models/docs009.py +++ b/docs_src/models/docs009.py @@ -1,9 +1,9 @@ from typing import Optional import databases +import ormar import sqlalchemy -import ormar from .docs010 import Artist # previous example database = databases.Database("sqlite:///test.db", force_rollback=True) diff --git a/docs_src/models/docs010.py b/docs_src/models/docs010.py index d63101edb..9bf904a51 100644 --- a/docs_src/models/docs010.py +++ b/docs_src/models/docs010.py @@ -1,7 +1,7 @@ import databases +import ormar import sqlalchemy -import ormar from .docs008 import Child database = databases.Database("sqlite:///test.db", force_rollback=True) diff --git a/docs_src/models/docs011.py b/docs_src/models/docs011.py index 962de1dc3..7f959240f 100644 --- a/docs_src/models/docs011.py +++ b/docs_src/models/docs011.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() @@ -16,4 +15,5 @@ class Meta: name: ormar.String(max_length=100) completed: ormar.Boolean(default=False) -c1 = Course() \ No newline at end of file + +c1 = Course() diff --git a/docs_src/models/docs012.py b/docs_src/models/docs012.py index 2c74a7707..ddc0d5b9d 100644 --- a/docs_src/models/docs012.py +++ b/docs_src/models/docs012.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs013.py b/docs_src/models/docs013.py index 8d584f3f8..b37927806 100644 --- a/docs_src/models/docs013.py +++ b/docs_src/models/docs013.py @@ -1,9 +1,8 @@ from typing import Optional import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///test.db", force_rollback=True) metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs014.py b/docs_src/models/docs014.py index fc02ddb2a..faca1f75c 100644 --- a/docs_src/models/docs014.py +++ b/docs_src/models/docs014.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs015.py b/docs_src/models/docs015.py index f3053b8c0..44a524249 100644 --- a/docs_src/models/docs015.py +++ b/docs_src/models/docs015.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy from ormar import property_field database = databases.Database("sqlite:///db.sqlite") diff --git a/docs_src/models/docs016.py b/docs_src/models/docs016.py index 5f9d71c84..21196dde4 100644 --- a/docs_src/models/docs016.py +++ b/docs_src/models/docs016.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs017.py b/docs_src/models/docs017.py index b1ba5e586..155f68c08 100644 --- a/docs_src/models/docs017.py +++ b/docs_src/models/docs017.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/models/docs018.py b/docs_src/models/docs018.py index d3aee4e1f..edc30958c 100644 --- a/docs_src/models/docs018.py +++ b/docs_src/models/docs018.py @@ -1,8 +1,8 @@ import datetime -import databases -import sqlalchemy +import databases import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/queries/docs002.py b/docs_src/queries/docs002.py index d9cdeffd6..7d18aa7d5 100644 --- a/docs_src/queries/docs002.py +++ b/docs_src/queries/docs002.py @@ -15,14 +15,17 @@ class Meta: id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) author: str = ormar.String(max_length=100) - genre: str = ormar.String(max_length=100, default='Fiction', - choices=['Fiction', 'Adventure', 'Historic', 'Fantasy']) + genre: str = ormar.String( + max_length=100, + default="Fiction", + choices=["Fiction", "Adventure", "Historic", "Fantasy"], + ) -await Book.objects.create(title='Tom Sawyer', author="Twain, Mark", genre='Adventure') -await Book.objects.create(title='War and Peace', author="Tolstoy, Leo", genre='Fiction') -await Book.objects.create(title='Anna Karenina', author="Tolstoy, Leo", genre='Fiction') +await Book.objects.create(title="Tom Sawyer", author="Twain, Mark", genre="Adventure") +await Book.objects.create(title="War and Peace", author="Tolstoy, Leo", genre="Fiction") +await Book.objects.create(title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction") -await Book.objects.update(each=True, genre='Fiction') -all_books = await Book.objects.filter(genre='Fiction').all() +await Book.objects.update(each=True, genre="Fiction") +all_books = await Book.objects.filter(genre="Fiction").all() assert len(all_books) == 3 diff --git a/docs_src/queries/docs003.py b/docs_src/queries/docs003.py index 58e4f1b50..d8b3b6594 100644 --- a/docs_src/queries/docs003.py +++ b/docs_src/queries/docs003.py @@ -15,18 +15,23 @@ class Meta: id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) author: str = ormar.String(max_length=100) - genre: str = ormar.String(max_length=100, default='Fiction', - choices=['Fiction', 'Adventure', 'Historic', 'Fantasy']) + genre: str = ormar.String( + max_length=100, + default="Fiction", + choices=["Fiction", "Adventure", "Historic", "Fantasy"], + ) -await Book.objects.create(title='Tom Sawyer', author="Twain, Mark", genre='Adventure') -await Book.objects.create(title='War and Peace', author="Tolstoy, Leo", genre='Fiction') -await Book.objects.create(title='Anna Karenina', author="Tolstoy, Leo", genre='Fiction') +await Book.objects.create(title="Tom Sawyer", author="Twain, Mark", genre="Adventure") +await Book.objects.create(title="War and Peace", author="Tolstoy, Leo", genre="Fiction") +await Book.objects.create(title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction") # if not exist the instance will be persisted in db -vol2 = await Book.objects.update_or_create(title="Volume II", author='Anonymous', genre='Fiction') +vol2 = await Book.objects.update_or_create( + title="Volume II", author="Anonymous", genre="Fiction" +) assert await Book.objects.count() == 1 # if pk or pkname passed in kwargs (like id here) the object will be updated -assert await Book.objects.update_or_create(id=vol2.id, genre='Historic') +assert await Book.objects.update_or_create(id=vol2.id, genre="Historic") assert await Book.objects.count() == 1 diff --git a/docs_src/queries/docs005.py b/docs_src/queries/docs005.py index dca07572d..01111236c 100644 --- a/docs_src/queries/docs005.py +++ b/docs_src/queries/docs005.py @@ -15,16 +15,21 @@ class Meta: id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) author: str = ormar.String(max_length=100) - genre: str = ormar.String(max_length=100, default='Fiction', - choices=['Fiction', 'Adventure', 'Historic', 'Fantasy']) + genre: str = ormar.String( + max_length=100, + default="Fiction", + choices=["Fiction", "Adventure", "Historic", "Fantasy"], + ) -await Book.objects.create(title='Tom Sawyer', author="Twain, Mark", genre='Adventure') -await Book.objects.create(title='War and Peace in Space', author="Tolstoy, Leo", genre='Fantasy') -await Book.objects.create(title='Anna Karenina', author="Tolstoy, Leo", genre='Fiction') +await Book.objects.create(title="Tom Sawyer", author="Twain, Mark", genre="Adventure") +await Book.objects.create( + title="War and Peace in Space", author="Tolstoy, Leo", genre="Fantasy" +) +await Book.objects.create(title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction") # delete accepts kwargs that will be used in filter # acting in same way as queryset.filter(**kwargs).delete() -await Book.objects.delete(genre='Fantasy') # delete all fantasy books +await Book.objects.delete(genre="Fantasy") # delete all fantasy books all_books = await Book.objects.all() assert len(all_books) == 2 diff --git a/docs_src/queries/docs006.py b/docs_src/queries/docs006.py index 13143d266..2a26b7005 100644 --- a/docs_src/queries/docs006.py +++ b/docs_src/queries/docs006.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -36,10 +35,27 @@ class Meta: # build some sample data toyota = await Company.objects.create(name="Toyota", founded=1937) -await Car.objects.create(manufacturer=toyota, name="Corolla", year=2020, gearbox_type='Manual', gears=5, - aircon_type='Manual') -await Car.objects.create(manufacturer=toyota, name="Yaris", year=2019, gearbox_type='Manual', gears=5, - aircon_type='Manual') -await Car.objects.create(manufacturer=toyota, name="Supreme", year=2020, gearbox_type='Auto', gears=6, - aircon_type='Auto') - +await Car.objects.create( + manufacturer=toyota, + name="Corolla", + year=2020, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", +) +await Car.objects.create( + manufacturer=toyota, + name="Yaris", + year=2019, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", +) +await Car.objects.create( + manufacturer=toyota, + name="Supreme", + year=2020, + gearbox_type="Auto", + gears=6, + aircon_type="Auto", +) diff --git a/docs_src/queries/docs007.py b/docs_src/queries/docs007.py index 7e8ddc03a..000462cef 100644 --- a/docs_src/queries/docs007.py +++ b/docs_src/queries/docs007.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/docs_src/queries/docs008.py b/docs_src/queries/docs008.py index 2c79b618d..8ee2c5921 100644 --- a/docs_src/queries/docs008.py +++ b/docs_src/queries/docs008.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -36,33 +35,65 @@ class Meta: # build some sample data toyota = await Company.objects.create(name="Toyota", founded=1937) -await Car.objects.create(manufacturer=toyota, name="Corolla", year=2020, gearbox_type='Manual', gears=5, - aircon_type='Manual') -await Car.objects.create(manufacturer=toyota, name="Yaris", year=2019, gearbox_type='Manual', gears=5, - aircon_type='Manual') -await Car.objects.create(manufacturer=toyota, name="Supreme", year=2020, gearbox_type='Auto', gears=6, - aircon_type='Auto') +await Car.objects.create( + manufacturer=toyota, + name="Corolla", + year=2020, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", +) +await Car.objects.create( + manufacturer=toyota, + name="Yaris", + year=2019, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", +) +await Car.objects.create( + manufacturer=toyota, + name="Supreme", + year=2020, + gearbox_type="Auto", + gears=6, + aircon_type="Auto", +) # select manufacturer but only name - to include related models use notation {model_name}__{column} -all_cars = await Car.objects.select_related('manufacturer').exclude_fields( - ['year', 'gearbox_type', 'gears', 'aircon_type', 'company__founded']).all() +all_cars = ( + await Car.objects.select_related("manufacturer") + .exclude_fields( + ["year", "gearbox_type", "gears", "aircon_type", "company__founded"] + ) + .all() +) for car in all_cars: # excluded columns will yield None - assert all(getattr(car, x) is None for x in ['year', 'gearbox_type', 'gears', 'aircon_type']) + assert all( + getattr(car, x) is None + for x in ["year", "gearbox_type", "gears", "aircon_type"] + ) # included column on related models will be available, pk column is always included # even if you do not include it in fields list - assert car.manufacturer.name == 'Toyota' + assert car.manufacturer.name == "Toyota" # also in the nested related models - you cannot exclude pk - it's always auto added assert car.manufacturer.founded is None # fields() can be called several times, building up the columns to select # models selected in select_related but with no columns in fields list implies all fields -all_cars = await Car.objects.select_related('manufacturer').exclude_fields('year').exclude_fields( - ['gear', 'gearbox_type']).all() +all_cars = ( + await Car.objects.select_related("manufacturer") + .exclude_fields("year") + .exclude_fields(["gear", "gearbox_type"]) + .all() +) # all fiels from company model are selected -assert all_cars[0].manufacturer.name == 'Toyota' +assert all_cars[0].manufacturer.name == "Toyota" assert all_cars[0].manufacturer.founded == 1937 # cannot exclude mandatory model columns - company__name in this example - note usage of dict/set this time -await Car.objects.select_related('manufacturer').exclude_fields([{'company': {'name'}}]).all() +await Car.objects.select_related("manufacturer").exclude_fields( + [{"company": {"name"}}] +).all() # will raise pydantic ValidationError as company.name is required diff --git a/docs_src/queries/docs009.py b/docs_src/queries/docs009.py index 74ecc71a9..5e2bcedac 100644 --- a/docs_src/queries/docs009.py +++ b/docs_src/queries/docs009.py @@ -1,33 +1,29 @@ # 1. like in example above -await Car.objects.select_related('manufacturer').fields(['id', 'name', 'manufacturer__name']).all() +await Car.objects.select_related("manufacturer").fields( + ["id", "name", "manufacturer__name"] +).all() # 2. to mark a field as required use ellipsis -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': { - 'name': ...} - }).all() +await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": {"name": ...}} +).all() # 3. to include whole nested model use ellipsis -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': ... - }).all() +await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": ...} +).all() # 4. to specify fields at last nesting level you can also use set - equivalent to 2. above -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': {'name'} - }).all() +await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": {"name"}} +).all() # 5. of course set can have multiple fields -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': {'name', 'founded'} - }).all() +await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": {"name", "founded"}} +).all() # 6. you can include all nested fields but it will be equivalent of 3. above which is shorter -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': {'id', 'name', 'founded'} - }).all() +await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": {"id", "name", "founded"}} +).all() diff --git a/docs_src/relations/docs001.py b/docs_src/relations/docs001.py index 48307d2f2..39862469a 100644 --- a/docs_src/relations/docs001.py +++ b/docs_src/relations/docs001.py @@ -1,9 +1,8 @@ -from typing import Optional, Dict, Union +from typing import Dict, Optional, Union import databases -import sqlalchemy - import ormar +import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() diff --git a/docs_src/relations/docs002.py b/docs_src/relations/docs002.py index 9831ccb0a..378f41d7f 100644 --- a/docs_src/relations/docs002.py +++ b/docs_src/relations/docs002.py @@ -1,4 +1,4 @@ -from typing import Optional, Union, List +from typing import List, Optional import databases import ormar diff --git a/examples/fastapi_quick_start.py b/examples/fastapi_quick_start.py index 386a0d50d..61d1c1e6e 100644 --- a/examples/fastapi_quick_start.py +++ b/examples/fastapi_quick_start.py @@ -1,12 +1,11 @@ from typing import List, Optional import databases +import ormar import sqlalchemy import uvicorn from fastapi import FastAPI -import ormar - app = FastAPI() metadata = sqlalchemy.MetaData() database = databases.Database("sqlite:///test.db") diff --git a/examples/script_from_readme.py b/examples/script_from_readme.py index 0aff68222..72acdd9c1 100644 --- a/examples/script_from_readme.py +++ b/examples/script_from_readme.py @@ -1,9 +1,8 @@ from typing import Optional import databases -import pydantic - import ormar +import pydantic import sqlalchemy DATABASE_URL = "sqlite:///db.sqlite" diff --git a/ormar/__init__.py b/ormar/__init__.py index 1d9b9c220..1910b3c69 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -23,7 +23,6 @@ from importlib.metadata import version # type: ignore except ImportError: # pragma: no cover from importlib_metadata import version # type: ignore -from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I100 from ormar.decorators import ( # noqa: I100 post_bulk_update, post_delete, @@ -43,41 +42,43 @@ NoMatch, ) from ormar.fields import ( + DECODERS_MAP, + ENCODERS_MAP, + JSON, + SQL_ENCODERS_MAP, + UUID, BaseField, BigInteger, Boolean, - DECODERS_MAP, + CheckColumns, Date, DateTime, Decimal, - ENCODERS_MAP, EncryptBackends, Enum, Float, ForeignKey, ForeignKeyField, + IndexColumns, Integer, - JSON, LargeBinary, ManyToMany, ManyToManyField, - SQL_ENCODERS_MAP, + ReferentialAction, SmallInteger, String, Text, Time, - UUID, UniqueColumns, - IndexColumns, - CheckColumns, - ReferentialAction, -) # noqa: I100 +) + +# noqa: I100 from ormar.models import ExcludableItems, Extra, Model from ormar.models.metaclass import ModelMeta +from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I100 from ormar.queryset import OrderAction, QuerySet, and_, or_ from ormar.relations import RelationType from ormar.signals import Signal -from ormar.models import OrmarConfig class UndefinedType: # pragma no cover diff --git a/ormar/decorators/signals.py b/ormar/decorators/signals.py index 3e328e51a..b3b38b91d 100644 --- a/ormar/decorators/signals.py +++ b/ormar/decorators/signals.py @@ -1,4 +1,4 @@ -from typing import Callable, List, TYPE_CHECKING, Type, Union +from typing import TYPE_CHECKING, Callable, List, Type, Union if TYPE_CHECKING: # pragma: no cover from ormar import Model diff --git a/ormar/fields/__init__.py b/ormar/fields/__init__.py index 08fec4f35..a9dcd7f2d 100644 --- a/ormar/fields/__init__.py +++ b/ormar/fields/__init__.py @@ -5,10 +5,12 @@ Also a definition for custom CHAR based sqlalchemy UUID field """ from ormar.fields.base import BaseField -from ormar.fields.constraints import IndexColumns, UniqueColumns, CheckColumns +from ormar.fields.constraints import CheckColumns, IndexColumns, UniqueColumns from ormar.fields.foreign_key import ForeignKey, ForeignKeyField from ormar.fields.many_to_many import ManyToMany, ManyToManyField from ormar.fields.model_fields import ( + JSON, + UUID, BigInteger, Boolean, Date, @@ -17,18 +19,16 @@ Enum, Float, Integer, - JSON, LargeBinary, SmallInteger, String, Text, Time, - UUID, ) from ormar.fields.parsers import DECODERS_MAP, ENCODERS_MAP, SQL_ENCODERS_MAP +from ormar.fields.referential_actions import ReferentialAction from ormar.fields.sqlalchemy_encrypted import EncryptBackend, EncryptBackends from ormar.fields.through_field import Through, ThroughField -from ormar.fields.referential_actions import ReferentialAction __all__ = [ "Decimal", diff --git a/ormar/fields/base.py b/ormar/fields/base.py index dd4602516..7f6cee669 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -1,5 +1,5 @@ import warnings -from typing import Any, Dict, List, Optional, TYPE_CHECKING, Type, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union import sqlalchemy from pydantic import typing @@ -14,8 +14,7 @@ ) if TYPE_CHECKING: # pragma no cover - from ormar.models import Model - from ormar.models import NewBaseModel + from ormar.models import Model, NewBaseModel class BaseField(FieldInfo): diff --git a/ormar/fields/constraints.py b/ormar/fields/constraints.py index e799d0ca6..e2f684093 100644 --- a/ormar/fields/constraints.py +++ b/ormar/fields/constraints.py @@ -1,6 +1,6 @@ from typing import Any -from sqlalchemy import Index, UniqueConstraint, CheckConstraint +from sqlalchemy import CheckConstraint, Index, UniqueConstraint class UniqueColumns(UniqueConstraint): diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index da2657bec..581164ba2 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -3,29 +3,29 @@ from dataclasses import dataclass from random import choices from typing import ( + TYPE_CHECKING, Any, Dict, ForwardRef, List, Optional, - TYPE_CHECKING, Tuple, Type, Union, overload, ) +import sqlalchemy +from pydantic import BaseModel, create_model import ormar # noqa I101 -import sqlalchemy from ormar.exceptions import ModelDefinitionError, RelationshipInstanceError from ormar.fields.base import BaseField from ormar.fields.referential_actions import ReferentialAction -from pydantic import BaseModel, create_model if TYPE_CHECKING: # pragma no cover - from ormar.models import Model, NewBaseModel, T from ormar.fields import ManyToManyField + from ormar.models import Model, NewBaseModel, T def create_dummy_instance(fk: Type["T"], pk: Any = None) -> "T": diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 9b904923c..a23ec6c67 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -1,10 +1,10 @@ import sys from typing import ( + TYPE_CHECKING, Any, ForwardRef, List, Optional, - TYPE_CHECKING, Tuple, Type, Union, @@ -12,14 +12,13 @@ overload, ) - import ormar # noqa: I100 from ormar import ModelDefinitionError from ormar.fields import BaseField from ormar.fields.foreign_key import ( ForeignKeyField, - validate_not_allowed_fields, create_dummy_model, + validate_not_allowed_fields, ) if TYPE_CHECKING: # pragma no cover diff --git a/ormar/fields/model_fields.py b/ormar/fields/model_fields.py index 16ab80c76..f7405b8e7 100644 --- a/ormar/fields/model_fields.py +++ b/ormar/fields/model_fields.py @@ -1,8 +1,9 @@ import datetime import decimal import uuid -from enum import Enum as E, EnumMeta -from typing import Any, Optional, Set, TYPE_CHECKING, Type, TypeVar, Union, overload +from enum import Enum as E +from enum import EnumMeta +from typing import TYPE_CHECKING, Any, Optional, Type, TypeVar, Union, overload import pydantic import sqlalchemy @@ -757,7 +758,6 @@ def get_column_type(cls, **kwargs: Any) -> Any: if TYPE_CHECKING: # pragma: nocover - T = TypeVar("T", bound=E) def Enum(enum_class: Type[T], **kwargs: Any) -> T: @@ -776,7 +776,6 @@ class Enum(ModelFieldFactory): def __new__( # type: ignore # noqa CFQ002 cls, *, enum_class: Type[E], **kwargs: Any ) -> BaseField: - kwargs = { **kwargs, **{ diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index ae92c2f95..dcc3f6cbe 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -33,7 +33,7 @@ def encode_decimal(value: decimal.Decimal, precision: int = None) -> float: def encode_bytes(value: Union[str, bytes], represent_as_string: bool = False) -> bytes: if represent_as_string: - value= value if isinstance(value, bytes) else base64.b64decode(value) + value = value if isinstance(value, bytes) else base64.b64decode(value) else: value = value if isinstance(value, bytes) else value.encode("utf-8") return value diff --git a/ormar/fields/sqlalchemy_encrypted.py b/ormar/fields/sqlalchemy_encrypted.py index 88dc0af73..90518e33a 100644 --- a/ormar/fields/sqlalchemy_encrypted.py +++ b/ormar/fields/sqlalchemy_encrypted.py @@ -2,7 +2,7 @@ import abc import base64 from enum import Enum -from typing import Any, Callable, Optional, TYPE_CHECKING, Type, Union +from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union import sqlalchemy.types as types from pydantic.utils import lenient_issubclass diff --git a/ormar/fields/through_field.py b/ormar/fields/through_field.py index a469ab3d8..d5ece7879 100644 --- a/ormar/fields/through_field.py +++ b/ormar/fields/through_field.py @@ -1,13 +1,14 @@ import sys -from typing import Any, TYPE_CHECKING, Type, Union +from typing import TYPE_CHECKING, Any, Type, Union from ormar.fields.base import BaseField from ormar.fields.foreign_key import ForeignKeyField if TYPE_CHECKING: # pragma no cover - from ormar import Model from pydantic.typing import ForwardRef + from ormar import Model + if sys.version_info < (3, 7): ToType = Type[Model] else: diff --git a/ormar/models/descriptors/descriptors.py b/ormar/models/descriptors/descriptors.py index 9030b0bdd..f8ea6043f 100644 --- a/ormar/models/descriptors/descriptors.py +++ b/ormar/models/descriptors/descriptors.py @@ -1,5 +1,5 @@ import base64 -from typing import Any, List, TYPE_CHECKING, Type +from typing import TYPE_CHECKING, Any, List, Type from ormar.fields.parsers import encode_json @@ -120,7 +120,9 @@ def __set__(self, instance: "Model", value: Any) -> None: instance.__dict__[self.name] = model instance.set_save_status(False) - def _populate_models_dict_if_not_present(self, instance: "Model", model: Any) -> None: + def _populate_models_dict_if_not_present( + self, instance: "Model", model: Any + ) -> None: models = instance.__dict__[self.name] if isinstance(model, list): for model_ in model: diff --git a/ormar/models/excludable.py b/ormar/models/excludable.py index 59125c5d0..ac851d031 100644 --- a/ormar/models/excludable.py +++ b/ormar/models/excludable.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Dict, List, Set, TYPE_CHECKING, Tuple, Type, Union +from typing import TYPE_CHECKING, Dict, List, Set, Tuple, Type, Union from ormar.queryset.utils import get_relationship_alias_model_and_str diff --git a/ormar/models/helpers/__init__.py b/ormar/models/helpers/__init__.py index 21d9f1ecb..8b5662b0b 100644 --- a/ormar/models/helpers/__init__.py +++ b/ormar/models/helpers/__init__.py @@ -1,7 +1,7 @@ from ormar.models.helpers.models import ( check_required_meta_parameters, - extract_annotations_and_default_vals, config_field_not_set, + extract_annotations_and_default_vals, populate_default_options_values, ) from ormar.models.helpers.pydantic import ( @@ -12,9 +12,9 @@ ) from ormar.models.helpers.relations import ( alias_manager, + expand_reverse_relationships, register_relation_in_alias_manager, ) -from ormar.models.helpers.relations import expand_reverse_relationships from ormar.models.helpers.sqlalchemy import ( populate_meta_sqlalchemy_table_if_required, populate_meta_tablename_columns_and_pk, diff --git a/ormar/models/helpers/models.py b/ormar/models/helpers/models.py index 05ec0dee0..d9c8af008 100644 --- a/ormar/models/helpers/models.py +++ b/ormar/models/helpers/models.py @@ -1,17 +1,15 @@ import itertools import sqlite3 -from typing import Any, Dict, List, TYPE_CHECKING, Tuple, Type +from typing import TYPE_CHECKING, Any, Dict, ForwardRef, List, Tuple, Type import pydantic -from typing import ForwardRef + import ormar # noqa: I100 from ormar.models.helpers.pydantic import populate_pydantic_default_values -from ormar.models.utils import Extra if TYPE_CHECKING: # pragma no cover from ormar import Model from ormar.fields import BaseField - from ormar.queryset import QuerySet def is_field_an_forward_ref(field: "BaseField") -> bool: diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index b7d78a338..c8eb01373 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -1,12 +1,10 @@ -import inspect from types import MappingProxyType -from typing import Dict, Optional, TYPE_CHECKING, Tuple, Type, Union +from typing import TYPE_CHECKING, Dict, Optional, Tuple, Type, Union import pydantic from pydantic import ConfigDict -from pydantic.fields import Field, FieldInfo +from pydantic.fields import FieldInfo from pydantic.utils import lenient_issubclass -from pydantic_core import PydanticUndefined from ormar.exceptions import ModelDefinitionError # noqa: I100, I202 from ormar.fields import BaseField diff --git a/ormar/models/helpers/related_names_validation.py b/ormar/models/helpers/related_names_validation.py index bd4df64c0..d086ed031 100644 --- a/ormar/models/helpers/related_names_validation.py +++ b/ormar/models/helpers/related_names_validation.py @@ -1,6 +1,5 @@ -from typing import Dict, List, Optional, TYPE_CHECKING, Type +from typing import TYPE_CHECKING, Dict, ForwardRef, List, Optional, Type -from typing import ForwardRef import ormar # noqa: I100 if TYPE_CHECKING: # pragma no cover diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 8bd373d26..8ba7f1a4b 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -1,9 +1,8 @@ -import copy import inspect -from typing import List, TYPE_CHECKING, Optional, Type, Union, cast, Dict, Any +from typing import TYPE_CHECKING, Any, List, Optional, Type, Union, cast from pydantic import BaseModel, create_model, field_serializer -from pydantic._internal._decorators import Decorator, DecoratorInfos +from pydantic._internal._decorators import DecoratorInfos from pydantic.fields import FieldInfo from pydantic_core.core_schema import SerializerFunctionWrapHandler @@ -16,7 +15,7 @@ if TYPE_CHECKING: # pragma no cover from ormar import Model - from ormar.fields import ManyToManyField, ForeignKeyField + from ormar.fields import ForeignKeyField, ManyToManyField alias_manager = AliasManager() @@ -149,20 +148,26 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: model_field.to.model_fields[related_name] = FieldInfo.from_annotated_attribute( annotation=field_type, default=None ) - add_field_serializer_for_reverse_relations(to_model=model_field.to, related_name=related_name) + add_field_serializer_for_reverse_relations( + to_model=model_field.to, related_name=related_name + ) model_field.to.model_rebuild(force=True) setattr(model_field.to, related_name, RelationDescriptor(name=related_name)) -def add_field_serializer_for_reverse_relations(to_model: "Model", related_name: str) -> None: - def serialize(self, children: List['BaseModel'], handler: SerializerFunctionWrapHandler) -> Any: +def add_field_serializer_for_reverse_relations( + to_model: "Model", related_name: str +) -> None: + def serialize( + self, children: List["BaseModel"], handler: SerializerFunctionWrapHandler + ) -> Any: """ Serialize a list of nodes, handling circular references by excluding the children. """ try: return handler(children) except ValueError as exc: - if not str(exc).startswith('Circular reference'): + if not str(exc).startswith("Circular reference"): raise exc result = [] @@ -170,14 +175,16 @@ def serialize(self, children: List['BaseModel'], handler: SerializerFunctionWrap try: serialized = handler([child]) except ValueError as exc: - if not str(exc).startswith('Circular reference'): + if not str(exc).startswith("Circular reference"): raise exc result.append({child.ormar_config.pkname: child.pk}) else: result.append(serialized) return result - decorator = field_serializer(related_name, mode="wrap", check_fields=False)(serialize) + decorator = field_serializer(related_name, mode="wrap", check_fields=False)( + serialize + ) setattr(to_model, f"serialize_{related_name}", decorator) DecoratorInfos.build(to_model) diff --git a/ormar/models/helpers/sqlalchemy.py b/ormar/models/helpers/sqlalchemy.py index 8dedcc127..7c2830fb5 100644 --- a/ormar/models/helpers/sqlalchemy.py +++ b/ormar/models/helpers/sqlalchemy.py @@ -1,8 +1,7 @@ import logging -from typing import Dict, List, Optional, TYPE_CHECKING, Tuple, Type, Union +from typing import TYPE_CHECKING, Dict, ForwardRef, List, Optional, Tuple, Type, Union import sqlalchemy -from typing import ForwardRef import ormar # noqa: I100, I202 from ormar.models.descriptors import RelationDescriptor @@ -12,7 +11,7 @@ ) if TYPE_CHECKING: # pragma no cover - from ormar import Model, ModelMeta, ManyToManyField, BaseField, ForeignKeyField + from ormar import BaseField, ForeignKeyField, ManyToManyField, Model from ormar.models import NewBaseModel from ormar.models.ormar_config import OrmarConfig diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 97449b3da..71129bed2 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -2,17 +2,17 @@ import decimal import numbers from typing import ( + TYPE_CHECKING, Any, Callable, Dict, List, Set, - TYPE_CHECKING, Type, Union, ) -from pydantic import BeforeValidator, typing +from pydantic import typing try: import orjson as json @@ -20,7 +20,6 @@ import json # type: ignore # noqa: F401 import pydantic -from pydantic.fields import Field import ormar # noqa: I100, I202 from ormar.models.helpers.models import config_field_not_set @@ -169,7 +168,11 @@ def get_pydantic_example_repr(type_: Any) -> Any: """ if hasattr(type_, "__origin__"): if type_.__origin__ == Union: - values = tuple(get_pydantic_example_repr(x) for x in type_.__args__ if x is not type(None)) + values = tuple( + get_pydantic_example_repr(x) + for x in type_.__args__ + if x is not type(None) + ) if len(values) == 1: return values[0] return values @@ -274,4 +277,6 @@ def modify_schema_example(model: Type["Model"]) -> None: # noqa CCR001 :type model: Model class """ if not config_field_not_set(model=model, field_name="model_fields"): - model.model_config["json_schema_extra"] = construct_schema_function_without_choices() + model.model_config[ + "json_schema_extra" + ] = construct_schema_function_without_choices() diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index b979d2235..14c12c61d 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -1,16 +1,16 @@ import copy from typing import ( + TYPE_CHECKING, Any, + Callable, Dict, List, Optional, Set, - TYPE_CHECKING, Tuple, Type, Union, cast, - Callable, ) import databases @@ -18,17 +18,16 @@ import sqlalchemy from pydantic import field_serializer from pydantic._internal._generics import PydanticGenericMetadata -from pydantic._internal._model_construction import complete_model_class from pydantic.fields import ComputedFieldInfo, FieldInfo from pydantic_core.core_schema import SerializerFunctionWrapHandler from sqlalchemy.sql.schema import ColumnCollectionConstraint import ormar # noqa I100 import ormar.fields.constraints -from ormar.fields.constraints import UniqueColumns, IndexColumns, CheckColumns from ormar import ModelDefinitionError # noqa I100 from ormar.exceptions import ModelError from ormar.fields import BaseField +from ormar.fields.constraints import CheckColumns, IndexColumns, UniqueColumns from ormar.fields.foreign_key import ForeignKeyField from ormar.fields.many_to_many import ManyToManyField from ormar.models.descriptors import ( @@ -41,13 +40,13 @@ from ormar.models.descriptors.descriptors import BytesDescriptor from ormar.models.helpers import ( check_required_meta_parameters, + config_field_not_set, expand_reverse_relationships, extract_annotations_and_default_vals, get_potential_fields, merge_or_generate_pydantic_config, - config_field_not_set, - populate_default_options_values, modify_schema_example, + populate_default_options_values, populate_meta_sqlalchemy_table_if_required, populate_meta_tablename_columns_and_pk, register_relation_in_alias_manager, @@ -133,7 +132,9 @@ def add_property_fields(new_model: Type["Model"], attrs: Dict) -> None: # noqa: """ props = set() for var_name, value in attrs.items(): - if hasattr(value, "decorator_info") and isinstance(value.decorator_info, ComputedFieldInfo): + if hasattr(value, "decorator_info") and isinstance( + value.decorator_info, ComputedFieldInfo + ): props.add(var_name) if config_field_not_set(model=new_model, field_name="property_fields"): @@ -185,7 +186,9 @@ def verify_constraint_names( :type parent_value: List """ new_aliases = {x.name: x.get_alias() for x in model_fields.values()} - old_aliases = {x.name: x.get_alias() for x in base_class.ormar_config.model_fields.values()} + old_aliases = { + x.name: x.get_alias() for x in base_class.ormar_config.model_fields.values() + } old_aliases.update(new_aliases) constraints_columns = [x._pending_colargs for x in parent_value] for column_set in constraints_columns: @@ -243,9 +246,13 @@ def update_attrs_from_base_meta( # noqa: CCR001 params_to_update = ["metadata", "database", "constraints", "property_fields"] for param in params_to_update: - current_value = attrs.get("ormar_config", {}).__dict__.get(param, ormar.Undefined) + current_value = attrs.get("ormar_config", {}).__dict__.get( + param, ormar.Undefined + ) parent_value = ( - base_class.ormar_config.__dict__.get(param) if hasattr(base_class, "ormar_config") else None + base_class.ormar_config.__dict__.get(param) + if hasattr(base_class, "ormar_config") + else None ) if parent_value: if param == "constraints": @@ -320,7 +327,6 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 extra=through_class.ormar_config.extra, constraints=through_class.ormar_config.constraints, order_by=through_class.ormar_config.orders_by, - ) new_meta.columns = None new_meta.table = through_class.ormar_config.pkname @@ -569,8 +575,13 @@ def add_field_descriptor( else: setattr(new_model, name, PydanticDescriptor(name=name)) + def get_serializer(): - def serialize(self, value: Optional[pydantic.BaseModel], handler: SerializerFunctionWrapHandler) -> Any: + def serialize( + self, + value: Optional[pydantic.BaseModel], + handler: SerializerFunctionWrapHandler, + ) -> Any: """ Serialize a value if it's not expired weak reference. """ @@ -579,14 +590,13 @@ def serialize(self, value: Optional[pydantic.BaseModel], handler: SerializerFunc except ReferenceError: return None except ValueError as exc: - if not str(exc).startswith('Circular reference'): + if not str(exc).startswith("Circular reference"): raise exc return {value.ormar_config.pkname: value.pk} return serialize - class ModelMetaclass(pydantic._internal._model_construction.ModelMetaclass): def __new__( # type: ignore # noqa: CCR001 mcs: "ModelMetaclass", @@ -596,7 +606,7 @@ def __new__( # type: ignore # noqa: CCR001 __pydantic_generic_metadata__: Union[PydanticGenericMetadata, None] = None, __pydantic_reset_parent_namespace__: bool = True, _create_model_module: Union[str, None] = None, - **kwargs + **kwargs, ) -> "ModelMetaclass": """ Metaclass used by ormar Models that performs configuration @@ -643,7 +653,9 @@ def __new__( # type: ignore # noqa: CCR001 attrs["model_config"]["from_attributes"] = True for field_name, field in model_fields.items(): if field.is_relation: - decorator = field_serializer(field_name, mode="wrap", check_fields=False)(get_serializer()) + decorator = field_serializer( + field_name, mode="wrap", check_fields=False + )(get_serializer()) attrs[f"serialize_{field_name}"] = decorator new_model = super().__new__( @@ -654,7 +666,8 @@ def __new__( # type: ignore # noqa: CCR001 __pydantic_generic_metadata__=__pydantic_generic_metadata__, __pydantic_reset_parent_namespace__=__pydantic_reset_parent_namespace__, _create_model_module=_create_model_module, - **kwargs) + **kwargs, + ) add_cached_properties(new_model) @@ -682,9 +695,9 @@ def __new__( # type: ignore # noqa: CCR001 and new_model.ormar_config.pkname not in new_model.model_fields ): field_name = new_model.ormar_config.pkname - new_model.model_fields[field_name] = FieldInfo.from_annotated_attribute( - Optional[int], None - ) + new_model.model_fields[ + field_name + ] = FieldInfo.from_annotated_attribute(Optional[int], None) new_model.model_rebuild(force=True) for item in new_model.ormar_config.property_fields: diff --git a/ormar/models/mixins/alias_mixin.py b/ormar/models/mixins/alias_mixin.py index c4b2b983d..2f808cd9d 100644 --- a/ormar/models/mixins/alias_mixin.py +++ b/ormar/models/mixins/alias_mixin.py @@ -1,4 +1,4 @@ -from typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING, Dict class AliasMixin: diff --git a/ormar/models/mixins/excludable_mixin.py b/ormar/models/mixins/excludable_mixin.py index f99996ca0..b9d44eeac 100644 --- a/ormar/models/mixins/excludable_mixin.py +++ b/ormar/models/mixins/excludable_mixin.py @@ -1,11 +1,11 @@ from typing import ( + TYPE_CHECKING, AbstractSet, Any, Dict, List, Mapping, Set, - TYPE_CHECKING, Type, TypeVar, Union, diff --git a/ormar/models/mixins/merge_mixin.py b/ormar/models/mixins/merge_mixin.py index 7ef20778c..29f9a5538 100644 --- a/ormar/models/mixins/merge_mixin.py +++ b/ormar/models/mixins/merge_mixin.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, TYPE_CHECKING, cast +from typing import TYPE_CHECKING, Dict, List, Optional, cast import ormar from ormar.queryset.utils import translate_list_to_dict diff --git a/ormar/models/mixins/prefetch_mixin.py b/ormar/models/mixins/prefetch_mixin.py index b9a9aec72..1b8d1a933 100644 --- a/ormar/models/mixins/prefetch_mixin.py +++ b/ormar/models/mixins/prefetch_mixin.py @@ -1,4 +1,4 @@ -from typing import Callable, Dict, List, TYPE_CHECKING, Tuple, Type, cast +from typing import TYPE_CHECKING, Callable, Dict, List, Tuple, Type, cast from ormar.models.mixins.relation_mixin import RelationMixin @@ -38,7 +38,9 @@ def get_clause_target_and_filter_column_name( :rtype: Tuple[Type[Model], str] """ if reverse: - field_name = parent_model.ormar_config.model_fields[related].get_related_name() + field_name = parent_model.ormar_config.model_fields[ + related + ].get_related_name() field = target_model.ormar_config.model_fields[field_name] if field.is_multi: field = cast("ManyToManyField", field) diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index 599f90106..6a50c1d8f 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -2,27 +2,26 @@ import string from random import choices from typing import ( + TYPE_CHECKING, Any, Callable, Dict, List, Optional, Set, - TYPE_CHECKING, Type, Union, cast, ) import pydantic -from pydantic.fields import Field, FieldInfo +from pydantic.fields import Field from ormar.models.mixins.relation_mixin import RelationMixin # noqa: I100, I202 from ormar.queryset.utils import translate_list_to_dict class PydanticMixin(RelationMixin): - __cache__: Dict[str, Type[pydantic.BaseModel]] = {} if TYPE_CHECKING: # pragma: no cover diff --git a/ormar/models/mixins/relation_mixin.py b/ormar/models/mixins/relation_mixin.py index 0e6f4c107..9eacaab89 100644 --- a/ormar/models/mixins/relation_mixin.py +++ b/ormar/models/mixins/relation_mixin.py @@ -1,4 +1,4 @@ -from typing import Callable, Dict, List, Optional, Set, TYPE_CHECKING, cast +from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Set, cast from ormar import BaseField, ForeignKeyField from ormar.models.traversible import NodeList diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index 9fff1048b..f7eb7a1f3 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -2,6 +2,7 @@ import uuid from enum import Enum from typing import ( + TYPE_CHECKING, Any, Callable, Collection, @@ -9,7 +10,6 @@ List, Optional, Set, - TYPE_CHECKING, cast, ) diff --git a/ormar/models/model.py b/ormar/models/model.py index 38a3b740a..e354b23c7 100644 --- a/ormar/models/model.py +++ b/ormar/models/model.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING, TypeVar, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, TypeVar, Union import ormar.queryset # noqa I100 from ormar.exceptions import ModelPersistenceError, NoMatch diff --git a/ormar/models/model_row.py b/ormar/models/model_row.py index aa524b5f0..6ff4c4f1b 100644 --- a/ormar/models/model_row.py +++ b/ormar/models/model_row.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, TYPE_CHECKING, Tuple, Type, Union, cast +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, Union, cast try: from sqlalchemy.engine.result import ResultProxy # type: ignore diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index e773aa891..3ae65a4c9 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -1,6 +1,7 @@ import base64 import sys from typing import ( + TYPE_CHECKING, AbstractSet, Any, Dict, @@ -9,7 +10,6 @@ MutableSequence, Optional, Set, - TYPE_CHECKING, Tuple, Type, TypeVar, @@ -20,8 +20,7 @@ import databases import pydantic import sqlalchemy -from pydantic import BaseModel, ConfigDict - +from pydantic import BaseModel import ormar # noqa I100 from ormar.exceptions import ModelError, ModelPersistenceError @@ -161,7 +160,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # type: ignore new_kwargs.get(related), self, to_register=True ) - def __setattr__(self, name: str, value: Any) -> None: # noqa CCR001 """ Overwrites setattr in pydantic parent as otherwise descriptors are not called. @@ -760,7 +758,6 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 exclude_through_models=exclude_through_models, ) elif nested_model is not None: - model_dict = nested_model.dict( relation_map=self._skip_ellipsis( relation_map, field, default_return=dict() diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index 17702e693..3920997f3 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -7,9 +7,9 @@ from ormar import BaseField, ForeignKeyField, ManyToManyField from ormar.models.helpers import alias_manager from ormar.models.utils import Extra +from ormar.queryset.queryset import QuerySet from ormar.relations import AliasManager from ormar.signals import SignalEmitter -from ormar.queryset.queryset import QuerySet class OrmarConfig: @@ -31,7 +31,7 @@ def __init__( self.tablename = tablename self.orders_by = order_by or [] self.columns: List[sqlalchemy.Column] = [] - self.constraints= constraints or [] + self.constraints = constraints or [] self.model_fields: Dict[ str, Union[BaseField, ForeignKeyField, ManyToManyField] ] = {} @@ -66,5 +66,5 @@ def copy( exclude_parent_fields=exclude_parent_fields, queryset_class=queryset_class or self.queryset_class, extra=extra or self.extra, - constraints=constraints + constraints=constraints, ) diff --git a/ormar/models/traversible.py b/ormar/models/traversible.py index 8d4a527b7..6194cea76 100644 --- a/ormar/models/traversible.py +++ b/ormar/models/traversible.py @@ -1,4 +1,4 @@ -from typing import Any, List, Optional, TYPE_CHECKING, Type +from typing import TYPE_CHECKING, Any, List, Optional, Type if TYPE_CHECKING: # pragma no cover from ormar.models.mixins.relation_mixin import RelationMixin diff --git a/ormar/protocols/queryset_protocol.py b/ormar/protocols/queryset_protocol.py index a2c1d586a..4b7d78150 100644 --- a/ormar/protocols/queryset_protocol.py +++ b/ormar/protocols/queryset_protocol.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Sequence, Set, TYPE_CHECKING, Tuple, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Set, Tuple, Union try: from typing import Protocol diff --git a/ormar/queryset/__init__.py b/ormar/queryset/__init__.py index 32fbee48e..7f580747b 100644 --- a/ormar/queryset/__init__.py +++ b/ormar/queryset/__init__.py @@ -4,10 +4,7 @@ from ormar.queryset.actions import FilterAction, OrderAction, SelectAction from ormar.queryset.clause import and_, or_ from ormar.queryset.field_accessor import FieldAccessor -from ormar.queryset.queries import FilterQuery -from ormar.queryset.queries import LimitQuery -from ormar.queryset.queries import OffsetQuery -from ormar.queryset.queries import OrderQuery +from ormar.queryset.queries import FilterQuery, LimitQuery, OffsetQuery, OrderQuery from ormar.queryset.queryset import QuerySet __all__ = [ diff --git a/ormar/queryset/actions/filter_action.py b/ormar/queryset/actions/filter_action.py index dcc3636e8..f5ab83212 100644 --- a/ormar/queryset/actions/filter_action.py +++ b/ormar/queryset/actions/filter_action.py @@ -1,4 +1,4 @@ -from typing import Any, TYPE_CHECKING, Type +from typing import TYPE_CHECKING, Any, Type import sqlalchemy diff --git a/ormar/queryset/actions/query_action.py b/ormar/queryset/actions/query_action.py index ec5f250bd..b8bd65193 100644 --- a/ormar/queryset/actions/query_action.py +++ b/ormar/queryset/actions/query_action.py @@ -1,5 +1,5 @@ import abc -from typing import Any, List, TYPE_CHECKING, Type +from typing import TYPE_CHECKING, Any, List, Type import sqlalchemy diff --git a/ormar/queryset/actions/select_action.py b/ormar/queryset/actions/select_action.py index c18e6f6db..71a864ab0 100644 --- a/ormar/queryset/actions/select_action.py +++ b/ormar/queryset/actions/select_action.py @@ -1,5 +1,5 @@ import decimal -from typing import Any, Callable, TYPE_CHECKING, Type +from typing import TYPE_CHECKING, Any, Callable, Type import sqlalchemy diff --git a/ormar/queryset/clause.py b/ormar/queryset/clause.py index 7fd093350..a23bb0b6a 100644 --- a/ormar/queryset/clause.py +++ b/ormar/queryset/clause.py @@ -1,7 +1,7 @@ import itertools from dataclasses import dataclass from enum import Enum -from typing import Any, Generator, List, TYPE_CHECKING, Tuple, Type +from typing import TYPE_CHECKING, Any, Generator, List, Tuple, Type import sqlalchemy @@ -180,7 +180,6 @@ class QueryClause: def __init__( self, model_cls: Type["Model"], filter_clauses: List, select_related: List ) -> None: - self._select_related = select_related[:] self.filter_clauses = filter_clauses[:] diff --git a/ormar/queryset/field_accessor.py b/ormar/queryset/field_accessor.py index 071f9e7a2..81440e07c 100644 --- a/ormar/queryset/field_accessor.py +++ b/ormar/queryset/field_accessor.py @@ -1,4 +1,4 @@ -from typing import Any, TYPE_CHECKING, Type, cast +from typing import TYPE_CHECKING, Any, Type, cast from ormar.queryset.actions import OrderAction from ormar.queryset.actions.filter_action import METHODS_TO_OPERATORS diff --git a/ormar/queryset/join.py b/ormar/queryset/join.py index 6ef9be05c..2afeb624a 100644 --- a/ormar/queryset/join.py +++ b/ormar/queryset/join.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, TYPE_CHECKING, Tuple, Type, cast +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, cast import sqlalchemy from sqlalchemy import text @@ -8,9 +8,9 @@ from ormar.relations import AliasManager if TYPE_CHECKING: # pragma no cover - from ormar import Model, ManyToManyField - from ormar.queryset import OrderAction + from ormar import ManyToManyField, Model from ormar.models.excludable import ExcludableItems + from ormar.queryset import OrderAction class SqlJoin: diff --git a/ormar/queryset/queries/filter_query.py b/ormar/queryset/queries/filter_query.py index cb9b88023..e6b7e828c 100644 --- a/ormar/queryset/queries/filter_query.py +++ b/ormar/queryset/queries/filter_query.py @@ -1,6 +1,7 @@ from typing import List import sqlalchemy + from ormar.queryset.actions.filter_action import FilterAction diff --git a/ormar/queryset/queries/prefetch_query.py b/ormar/queryset/queries/prefetch_query.py index 3413bc4f5..66c2e47b9 100644 --- a/ormar/queryset/queries/prefetch_query.py +++ b/ormar/queryset/queries/prefetch_query.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Sequence, Set, TYPE_CHECKING, Tuple, Type, cast +from typing import TYPE_CHECKING, Dict, List, Sequence, Set, Tuple, Type, cast import ormar from ormar.queryset.clause import QueryClause @@ -7,9 +7,9 @@ if TYPE_CHECKING: # pragma: no cover from ormar import Model - from ormar.fields import ForeignKeyField, BaseField - from ormar.queryset import OrderAction + from ormar.fields import BaseField, ForeignKeyField from ormar.models.excludable import ExcludableItems + from ormar.queryset import OrderAction def sort_models(models: List["Model"], orders_by: Dict) -> List["Model"]: @@ -96,7 +96,6 @@ def __init__( # noqa: CFQ002 select_related: List, orders_by: List["OrderAction"], ) -> None: - self.model = model_cls self.database = self.model.ormar_config.database self._prefetch_related = prefetch_related @@ -473,14 +472,18 @@ async def _run_prefetch_query( select_related = [] query_target = target_model table_prefix = "" - exclude_prefix = target_field.to.ormar_config.alias_manager.resolve_relation_alias( - from_model=target_field.owner, relation_name=target_field.name + exclude_prefix = ( + target_field.to.ormar_config.alias_manager.resolve_relation_alias( + from_model=target_field.owner, relation_name=target_field.name + ) ) if target_field.is_multi: query_target = target_field.through select_related = [target_name] - table_prefix = target_field.to.ormar_config.alias_manager.resolve_relation_alias( - from_model=query_target, relation_name=target_name + table_prefix = ( + target_field.to.ormar_config.alias_manager.resolve_relation_alias( + from_model=query_target, relation_name=target_name + ) ) exclude_prefix = table_prefix self.already_extracted.setdefault(target_name, {})["prefix"] = table_prefix diff --git a/ormar/queryset/queries/query.py b/ormar/queryset/queries/query.py index acca91bdb..5a9ec9071 100644 --- a/ormar/queryset/queries/query.py +++ b/ormar/queryset/queries/query.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, TYPE_CHECKING, Tuple, Type, Union +from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type, Union import sqlalchemy from sqlalchemy import Table, text @@ -6,14 +6,14 @@ import ormar # noqa I100 from ormar.models.helpers.models import group_related_list -from ormar.queryset.queries import FilterQuery, LimitQuery, OffsetQuery, OrderQuery from ormar.queryset.actions.filter_action import FilterAction from ormar.queryset.join import SqlJoin +from ormar.queryset.queries import FilterQuery, LimitQuery, OffsetQuery, OrderQuery if TYPE_CHECKING: # pragma no cover from ormar import Model - from ormar.queryset import OrderAction from ormar.models.excludable import ExcludableItems + from ormar.queryset import OrderAction class Query: diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index 1fd72024c..809b22855 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -1,19 +1,19 @@ import asyncio from typing import ( + TYPE_CHECKING, Any, + AsyncGenerator, Dict, Generic, List, Optional, Sequence, Set, - TYPE_CHECKING, Tuple, Type, TypeVar, Union, cast, - AsyncGenerator, ) import databases @@ -46,8 +46,8 @@ class LegacyRow(dict): # type: ignore if TYPE_CHECKING: # pragma no cover from ormar import Model from ormar.models import T - from ormar.models.ormar_config import OrmarConfig from ormar.models.excludable import ExcludableItems + from ormar.models.ormar_config import OrmarConfig else: T = TypeVar("T", bound="Model") diff --git a/ormar/queryset/reverse_alias_resolver.py b/ormar/queryset/reverse_alias_resolver.py index 19a41a5b7..7cc4f8d3c 100644 --- a/ormar/queryset/reverse_alias_resolver.py +++ b/ormar/queryset/reverse_alias_resolver.py @@ -1,4 +1,4 @@ -from typing import Dict, List, TYPE_CHECKING, Type, cast +from typing import TYPE_CHECKING, Dict, List, Type, cast if TYPE_CHECKING: # pragma: no cover from ormar import ForeignKeyField, Model @@ -20,7 +20,9 @@ def __init__( ) -> None: self.select_related = select_related self.model_cls = model_cls - self.reversed_aliases = self.model_cls.ormar_config.alias_manager.reversed_aliases + self.reversed_aliases = ( + self.model_cls.ormar_config.alias_manager.reversed_aliases + ) self.excludable = excludable self.exclude_through = exclude_through diff --git a/ormar/queryset/utils.py b/ormar/queryset/utils.py index d858fd509..7bc9365dd 100644 --- a/ormar/queryset/utils.py +++ b/ormar/queryset/utils.py @@ -1,20 +1,20 @@ import collections.abc import copy from typing import ( + TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Set, - TYPE_CHECKING, Tuple, Type, Union, ) if TYPE_CHECKING: # pragma no cover - from ormar import Model, BaseField + from ormar import BaseField, Model def check_node_not_dict_or_not_last_node( diff --git a/ormar/relations/alias_manager.py b/ormar/relations/alias_manager.py index 4cd976a4b..9787f571e 100644 --- a/ormar/relations/alias_manager.py +++ b/ormar/relations/alias_manager.py @@ -1,15 +1,15 @@ import string import uuid from random import choices -from typing import Any, Dict, List, TYPE_CHECKING, Type, Union +from typing import TYPE_CHECKING, Any, Dict, List, Type, Union import sqlalchemy from sqlalchemy import text if TYPE_CHECKING: # pragma: no cover from ormar import Model - from ormar.models import ModelRow from ormar.fields import ForeignKeyField + from ormar.models import ModelRow def get_table_alias() -> str: diff --git a/ormar/relations/querysetproxy.py b/ormar/relations/querysetproxy.py index c47e37532..62f5882d2 100644 --- a/ormar/relations/querysetproxy.py +++ b/ormar/relations/querysetproxy.py @@ -1,6 +1,7 @@ -from _weakref import CallableProxyType from typing import ( # noqa: I100, I201 + TYPE_CHECKING, Any, + AsyncGenerator, Dict, Generic, List, @@ -8,23 +9,23 @@ Optional, Sequence, Set, - TYPE_CHECKING, Tuple, Type, TypeVar, Union, cast, - AsyncGenerator, ) +from _weakref import CallableProxyType + import ormar # noqa: I100, I202 from ormar.exceptions import ModelPersistenceError, NoMatch, QueryDefinitionError if TYPE_CHECKING: # pragma no cover - from ormar.relations import Relation + from ormar import OrderAction, RelationType from ormar.models import Model, T from ormar.queryset import QuerySet - from ormar import OrderAction, RelationType + from ormar.relations import Relation else: T = TypeVar("T", bound="Model") diff --git a/ormar/relations/relation.py b/ormar/relations/relation.py index e782d209c..b65db3035 100644 --- a/ormar/relations/relation.py +++ b/ormar/relations/relation.py @@ -1,10 +1,10 @@ from enum import Enum from typing import ( + TYPE_CHECKING, Generic, List, Optional, Set, - TYPE_CHECKING, Type, TypeVar, Union, @@ -16,8 +16,8 @@ from ormar.relations.relation_proxy import RelationProxy if TYPE_CHECKING: # pragma no cover - from ormar.relations import RelationsManager from ormar.models import Model, NewBaseModel, T + from ormar.relations import RelationsManager else: T = TypeVar("T", bound="Model") diff --git a/ormar/relations/relation_manager.py b/ormar/relations/relation_manager.py index ce47fe5e4..ad37e625a 100644 --- a/ormar/relations/relation_manager.py +++ b/ormar/relations/relation_manager.py @@ -1,12 +1,12 @@ -from typing import Dict, List, Optional, Sequence, TYPE_CHECKING, Type, Union +from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Type, Union from weakref import proxy from ormar.relations.relation import Relation, RelationType from ormar.relations.utils import get_relations_sides_and_names if TYPE_CHECKING: # pragma no cover - from ormar.models import NewBaseModel, Model - from ormar.fields import ForeignKeyField, BaseField + from ormar.fields import BaseField, ForeignKeyField + from ormar.models import Model, NewBaseModel class RelationsManager: diff --git a/ormar/relations/relation_proxy.py b/ormar/relations/relation_proxy.py index 63e33c041..7efaf41ab 100644 --- a/ormar/relations/relation_proxy.py +++ b/ormar/relations/relation_proxy.py @@ -1,14 +1,15 @@ from typing import ( + TYPE_CHECKING, Any, Dict, Generic, List, Optional, - TYPE_CHECKING, Set, Type, TypeVar, ) + from typing_extensions import SupportsIndex import ormar @@ -18,8 +19,8 @@ if TYPE_CHECKING: # pragma no cover from ormar import Model, RelationType from ormar.models import T - from ormar.relations import Relation from ormar.queryset import QuerySet + from ormar.relations import Relation else: T = TypeVar("T", bound="Model") diff --git a/ormar/signals/signal.py b/ormar/signals/signal.py index 868b494ec..ee952d6c8 100644 --- a/ormar/signals/signal.py +++ b/ormar/signals/signal.py @@ -1,6 +1,6 @@ import asyncio import inspect -from typing import Any, Callable, Dict, TYPE_CHECKING, Tuple, Type, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, Tuple, Type, Union from ormar.exceptions import SignalDefinitionError diff --git a/pyproject.toml b/pyproject.toml index 970b9447b..af367e112 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,5 +167,5 @@ split_arguments_when_comma_terminated = true [tool.ruff] select = ["E", "F", "I"] ignore = ["E402"] -line-length = 120 +line-length = 88 src = ["ormar", "tests"] diff --git a/tests/test_deferred/test_forward_cross_refs.py b/tests/test_deferred/test_forward_cross_refs.py index 43399517a..3e1aa747f 100644 --- a/tests/test_deferred/test_forward_cross_refs.py +++ b/tests/test_deferred/test_forward_cross_refs.py @@ -1,14 +1,12 @@ # type: ignore -from typing import List, Optional +from typing import ForwardRef, List, Optional import databases +import ormar import pytest import sqlalchemy as sa -from typing import ForwardRef from sqlalchemy import create_engine -import ormar -from ormar import ModelMeta from tests.settings import DATABASE_URL metadata = sa.MetaData() @@ -19,8 +17,8 @@ base_ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) @@ -35,7 +33,8 @@ class Student(ormar.Model): class StudentTeacher(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "students_x_teachers") + ormar_config = base_ormar_config.copy(tablename="students_x_teachers") + class Teacher(ormar.Model): ormar_config = base_ormar_config.copy() @@ -54,7 +53,7 @@ class Teacher(ormar.Model): class Country(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "countries") + ormar_config = base_ormar_config.copy(tablename="countries") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128) @@ -65,7 +64,7 @@ class Country(ormar.Model): class City(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "cities") + ormar_config = base_ormar_config.copy(tablename="cities") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128) diff --git a/tests/test_deferred/test_forward_refs.py b/tests/test_deferred/test_forward_refs.py index b31487446..0d2d31981 100644 --- a/tests/test_deferred/test_forward_refs.py +++ b/tests/test_deferred/test_forward_refs.py @@ -1,16 +1,14 @@ # type: ignore -from typing import List, Optional +from typing import ForwardRef, List, Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy as sa -from typing import ForwardRef +from ormar.exceptions import ModelError 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() @@ -22,8 +20,8 @@ class Person(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -40,8 +38,8 @@ class Person(ormar.Model): class Child(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -57,15 +55,15 @@ class Child(ormar.Model): class ChildFriend(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) class Game(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -98,8 +96,8 @@ async def test_not_updated_model_raises_errors(): class Person2(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -122,14 +120,14 @@ async def test_not_updated_model_m2m_raises_errors(): class PersonFriend(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) class Person3(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -154,8 +152,8 @@ async def test_not_updated_model_m2m_through_raises_errors(): class Pet(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -163,8 +161,8 @@ class Pet(ormar.Model): class Person4(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -175,8 +173,8 @@ class Person4(ormar.Model): class PersonPet(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, + metadata=metadata, + database=db, ) with pytest.raises(ModelError): diff --git a/tests/test_deferred/test_more_same_table_joins.py b/tests/test_deferred/test_more_same_table_joins.py index f06d28e28..820187ae1 100644 --- a/tests/test_deferred/test_more_same_table_joins.py +++ b/tests/test_deferred/test_more_same_table_joins.py @@ -1,11 +1,10 @@ -import asyncio from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -14,9 +13,9 @@ class Department(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "departments", - metadata = metadata, - database = database, + tablename="departments", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True, autoincrement=False) @@ -25,9 +24,9 @@ class Department(ormar.Model): class SchoolClass(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "schoolclasses", - metadata = metadata, - database = database, + tablename="schoolclasses", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -36,9 +35,9 @@ class SchoolClass(ormar.Model): class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - metadata = metadata, - database = database, + tablename="categories", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -48,9 +47,9 @@ class Category(ormar.Model): class Student(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "students", - metadata = metadata, - database = database, + tablename="students", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -61,9 +60,9 @@ class Student(ormar.Model): class Teacher(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "teachers", - metadata = metadata, - database = database, + tablename="teachers", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_deferred/test_same_table_joins.py b/tests/test_deferred/test_same_table_joins.py index c6e138e45..c6efc9302 100644 --- a/tests/test_deferred/test_same_table_joins.py +++ b/tests/test_deferred/test_same_table_joins.py @@ -1,11 +1,10 @@ -import asyncio from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -14,9 +13,9 @@ class Department(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "departments", - metadata = metadata, - database = database, + tablename="departments", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True, autoincrement=False) @@ -25,9 +24,9 @@ class Department(ormar.Model): class SchoolClass(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "schoolclasses", - metadata = metadata, - database = database, + tablename="schoolclasses", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -37,9 +36,9 @@ class SchoolClass(ormar.Model): class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - metadata = metadata, - database = database, + tablename="categories", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -48,9 +47,9 @@ class Category(ormar.Model): class Student(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "students", - metadata = metadata, - database = database, + tablename="students", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -61,9 +60,9 @@ class Student(ormar.Model): class Teacher(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "teachers", - metadata = metadata, - database = database, + tablename="teachers", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_encryption/test_encrypted_columns.py b/tests/test_encryption/test_encrypted_columns.py index c63d920c4..01546baf4 100644 --- a/tests/test_encryption/test_encrypted_columns.py +++ b/tests/test_encryption/test_encrypted_columns.py @@ -1,18 +1,18 @@ # type: ignore import base64 +import datetime import decimal import hashlib import uuid -import datetime from typing import Any import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar import ModelDefinitionError, NoMatch from ormar.fields.sqlalchemy_encrypted import EncryptedString + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -24,7 +24,9 @@ database=database, ) -default_fernet = dict(encrypt_secret="asd123", encrypt_backend=ormar.EncryptBackends.FERNET) +default_fernet = dict( + encrypt_secret="asd123", encrypt_backend=ormar.EncryptBackends.FERNET +) class DummyBackend(ormar.fields.EncryptBackend): diff --git a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py index 470b15730..f5b7244bf 100644 --- a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py +++ b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py @@ -2,12 +2,11 @@ from typing import List, Optional, Union import databases +import ormar as orm import pydantic import pytest import sqlalchemy -import ormar as orm - from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -169,7 +168,9 @@ class Changelog(orm.Model): content: str = orm.Text(default="") version: str = orm.Text(default="") past_changelog: int = orm.Integer(default=0) - label: Label = orm.ForeignKey(Label, nullable=True, ondelete="CASCADE", onupdate="CASCADE") + label: Label = orm.ForeignKey( + Label, nullable=True, ondelete="CASCADE", onupdate="CASCADE" + ) project: Project = orm.ForeignKey(Project, ondelete="CASCADE", onupdate="CASCADE") created_date: datetime = orm.DateTime(default=datetime.utcnow()) @@ -218,7 +219,9 @@ class MergeRequest(orm.Model): class Push(orm.Model): id: int = orm.Integer(name="id", primary_key=True) - branch: Branch = orm.ForeignKey(Branch, nullable=True, ondelete="CASCADE", onupdate="CASCADE") + branch: Branch = orm.ForeignKey( + Branch, nullable=True, ondelete="CASCADE", onupdate="CASCADE" + ) has_locking_changes: bool = orm.Boolean(default=False) sha: str = orm.String(max_length=200) labels: Optional[Union[List[Label], Label]] = orm.ManyToMany( @@ -259,8 +262,12 @@ class Tag(orm.Model): labels: Optional[Union[List[Label], Label]] = orm.ManyToMany( Label, through=TagLabel, ondelete="CASCADE", onupdate="CASCADE" ) - user: User = orm.ForeignKey(User, nullable=True, ondelete="CASCADE", onupdate="CASCADE") - branch: Branch = orm.ForeignKey(Branch, nullable=True, ondelete="CASCADE", onupdate="CASCADE") + user: User = orm.ForeignKey( + User, nullable=True, ondelete="CASCADE", onupdate="CASCADE" + ) + branch: Branch = orm.ForeignKey( + Branch, nullable=True, ondelete="CASCADE", onupdate="CASCADE" + ) ormar_config = base_ormar_config.copy(tablename="tags") @@ -282,9 +289,15 @@ class Webhook(orm.Model): id: int = orm.Integer(name="id", primary_key=True) object_kind = orm.String(max_length=100) project: Project = orm.ForeignKey(Project, ondelete="CASCADE", onupdate="CASCADE") - merge_request: MergeRequest = orm.ForeignKey(MergeRequest, nullable=True, ondelete="CASCADE", onupdate="CASCADE") - tag: Tag = orm.ForeignKey(Tag, nullable=True, ondelete="CASCADE", onupdate="CASCADE") - push: Push = orm.ForeignKey(Push, nullable=True, ondelete="CASCADE", onupdate="CASCADE") + merge_request: MergeRequest = orm.ForeignKey( + MergeRequest, nullable=True, ondelete="CASCADE", onupdate="CASCADE" + ) + tag: Tag = orm.ForeignKey( + Tag, nullable=True, ondelete="CASCADE", onupdate="CASCADE" + ) + push: Push = orm.ForeignKey( + Push, nullable=True, ondelete="CASCADE", onupdate="CASCADE" + ) created_at: datetime = orm.DateTime(default=datetime.now()) data: pydantic.Json = orm.JSON(default={}) status: int = orm.Integer(default=200) @@ -312,7 +325,14 @@ async def test_very_complex_relation_map(): { "id": 9, "title": "prueba-2321", - "description": "\n\n### [v.1.3.0.0] - 2021-08-19\n#### Resolved Issues\n\n#### Task\n\n- Probar flujo de changelog Automatic Jira: [SAN-86](https://htech.atlassian.net/browse/SAN-86)\n\n Description: Se probara el flujo de changelog automatic. \n\n Changelog: Se agrega función para extraer texto del campo changelog del dashboard de Sanval y ponerlo directamente en el changelog.md del repositorio. \n\n\n \n\n", + "description": "\n\n### [v.1.3.0.0] - 2021-08-19\n" + "#### Resolved Issues\n\n" + "#### Task\n\n- Probar flujo de changelog Automatic Jira: " + "[SAN-86](https://htech.atlassian.net/browse/SAN-86)\n\n " + "Description: Se probara el flujo de changelog automatic. \n\n " + "Changelog: Se agrega función para extraer texto del campo changelog del " + "dashboard de Sanval y ponerlo directamente en el changelog.md del repositorio." + " \n\n\n \n\n", "data": {}, }, { diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index e2e1dbde3..bb6ca6965 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -1,10 +1,10 @@ from typing import List, Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() diff --git a/tests/test_exclude_include_dict/test_excludable_items.py b/tests/test_exclude_include_dict/test_excludable_items.py index 37cf0be0b..c93f6a691 100644 --- a/tests/test_exclude_include_dict/test_excludable_items.py +++ b/tests/test_exclude_include_dict/test_excludable_items.py @@ -1,10 +1,10 @@ from typing import List, Optional import databases -import sqlalchemy - import ormar +import sqlalchemy from ormar.models.excludable import ExcludableItems + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -65,7 +65,9 @@ def compare_results(excludable): assert car_excludable.is_excluded("year") - alias = Company.ormar_config.alias_manager.resolve_relation_alias(Car, "manufacturer") + alias = Company.ormar_config.alias_manager.resolve_relation_alias( + Car, "manufacturer" + ) manu_excludable = excludable.get(Company, alias=alias) assert manu_excludable.exclude == {"founded"} assert manu_excludable.include == set() @@ -200,7 +202,9 @@ def test_includes_and_excludes_combo(): assert car_excludable.is_excluded("aircon_type") assert car_excludable.is_included("name") - alias = Company.ormar_config.alias_manager.resolve_relation_alias(Car, "manufacturer") + alias = Company.ormar_config.alias_manager.resolve_relation_alias( + Car, "manufacturer" + ) manu_excludable = excludable.get(Company, alias=alias) assert manu_excludable.include == {"name"} assert manu_excludable.exclude == {"founded"} diff --git a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py index eef49d4a5..c67b1c995 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py @@ -1,18 +1,18 @@ import datetime -import string import random +import string import databases +import ormar import pydantic import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient +from ormar import post_save from pydantic import computed_field -import ormar -from ormar import post_save from tests.settings import DATABASE_URL app = FastAPI() @@ -72,7 +72,9 @@ class RandomModel(ormar.Model): password: str = ormar.String(max_length=255, default=gen_pass) first_name: str = ormar.String(max_length=255, default="John") last_name: str = ormar.String(max_length=255) - created_date: datetime.datetime = ormar.DateTime(server_default=sqlalchemy.func.now()) + created_date: datetime.datetime = ormar.DateTime( + server_default=sqlalchemy.func.now() + ) @computed_field def full_name(self) -> str: @@ -107,7 +109,9 @@ class User2(ormar.Model): first_name: str = ormar.String(max_length=255) last_name: str = ormar.String(max_length=255) category: str = ormar.String(max_length=255, nullable=True) - timestamp: datetime.datetime = ormar.DateTime(pydantic_only=True, default=datetime.datetime.now) + timestamp: datetime.datetime = ormar.DateTime( + pydantic_only=True, default=datetime.datetime.now + ) @pytest.fixture(autouse=True, scope="module") @@ -220,7 +224,12 @@ async def test_excluding_fields_in_endpoints(): "category", "timestamp", ] - assert datetime.datetime.strptime(response.json().get("timestamp"), "%Y-%m-%dT%H:%M:%S.%f") == timestamp + assert ( + datetime.datetime.strptime( + response.json().get("timestamp"), "%Y-%m-%dT%H:%M:%S.%f" + ) + == timestamp + ) @pytest.mark.asyncio @@ -271,7 +280,6 @@ async def test_adding_fields_in_endpoints2(): @pytest.mark.asyncio async def test_excluding_property_field_in_endpoints2(): - dummy_registry = {} @post_save(RandomModel) diff --git a/tests/test_exclude_include_dict/test_excluding_fields_with_default.py b/tests/test_exclude_include_dict/test_excluding_fields_with_default.py index 250a1d1fe..b754672a9 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_with_default.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_with_default.py @@ -2,10 +2,10 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -103,7 +103,9 @@ async def test_excluding_field_with_default(): album = ( await Album.objects.select_related("tracks") - .exclude_fields({"is_best_seller": ..., "tracks": {"play_count", "position"}}) + .exclude_fields( + {"is_best_seller": ..., "tracks": {"play_count", "position"}} + ) .get(name="Miami") ) assert album.is_best_seller is None diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index 591fd6a34..860ac519b 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -1,11 +1,11 @@ from typing import Optional import databases +import ormar import pydantic import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -14,9 +14,9 @@ class Company(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "companies", - metadata = metadata, - database = database, + tablename="companies", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -26,9 +26,9 @@ class Company(ormar.Model): class Car(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "cars", - metadata = metadata, - database = database, + tablename="cars", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_exclude_include_dict/test_pydantic_dict_params.py b/tests/test_exclude_include_dict/test_pydantic_dict_params.py index 6a925193d..40bbdc01d 100644 --- a/tests/test_exclude_include_dict/test_pydantic_dict_params.py +++ b/tests/test_exclude_include_dict/test_pydantic_dict_params.py @@ -1,10 +1,10 @@ from typing import List import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() @@ -97,7 +97,9 @@ async def test_exclude_none(): "items": [], "visibility": True, } - assert category2.json(exclude_none=True) == '{"id":2,"visibility":true,"items":[]}' + assert ( + category2.json(exclude_none=True) == '{"id":2,"visibility":true,"items":[]}' + ) @pytest.mark.asyncio diff --git a/tests/test_fastapi/test_binary_fields.py b/tests/test_fastapi/test_binary_fields.py index 354941006..d8436f173 100644 --- a/tests/test_fastapi/test_binary_fields.py +++ b/tests/test_fastapi/test_binary_fields.py @@ -4,13 +4,13 @@ from typing import List import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL app = FastAPI() @@ -56,7 +56,7 @@ class BinaryEnum(Enum): class BinaryThing(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "things") + ormar_config = base_ormar_config.copy(tablename="things") id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.Text(default="") diff --git a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py index a4a8465ca..c7f285fa5 100644 --- a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py +++ b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py @@ -2,14 +2,13 @@ from uuid import UUID, uuid4 import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -import ormar - app = FastAPI() DATABASE_URL = "sqlite:///db.sqlite" database = databases.Database(DATABASE_URL) @@ -21,15 +20,16 @@ database=database, ) + class CA(ormar.Model): - ormar_config = base_ormar_config.copy( tablename = "cas") + ormar_config = base_ormar_config.copy(tablename="cas") id: UUID = ormar.UUID(primary_key=True, default=uuid4) ca_name: str = ormar.Text(default="") class CB1(ormar.Model): - ormar_config = base_ormar_config.copy( tablename = "cb1s") + ormar_config = base_ormar_config.copy(tablename="cb1s") id: UUID = ormar.UUID(primary_key=True, default=uuid4) cb1_name: str = ormar.Text(default="") @@ -37,7 +37,7 @@ class CB1(ormar.Model): class CB2(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "cb2s") + ormar_config = base_ormar_config.copy(tablename="cb2s") id: UUID = ormar.UUID(primary_key=True, default=uuid4) cb2_name: str = ormar.Text(default="") diff --git a/tests/test_fastapi/test_enum_schema.py b/tests/test_fastapi/test_enum_schema.py index a7d487851..fa1ac6b5b 100644 --- a/tests/test_fastapi/test_enum_schema.py +++ b/tests/test_fastapi/test_enum_schema.py @@ -1,9 +1,9 @@ from enum import Enum import databases +import ormar import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_fastapi/test_excludes_with_get_pydantic.py b/tests/test_fastapi/test_excludes_with_get_pydantic.py index 6699f4a8f..ca4f42160 100644 --- a/tests/test_fastapi/test_excludes_with_get_pydantic.py +++ b/tests/test_fastapi/test_excludes_with_get_pydantic.py @@ -10,7 +10,7 @@ SelfRef, database, metadata, -) # type: ignore +) app = FastAPI() app.state.database = database @@ -51,9 +51,9 @@ async def create_category(category: Category): response_model=SelfRef.get_pydantic(exclude={"parent", "children__name"}), ) async def create_selfref( - selfref: SelfRef.get_pydantic( # type: ignore - exclude={"children__name"} # noqa: F821 - ), + selfref: SelfRef.get_pydantic( # type: ignore + exclude={"children__name"} # noqa: F821 + ), ): selfr = SelfRef(**selfref.dict()) await selfr.save() @@ -133,8 +133,8 @@ async def test_read_main(): assert response.status_code == 200 check_children = SelfRef(**response.json()) assert check_children.dict() == { - 'children': [{'id': 2, 'name': 'test2'}], - 'id': 1, - 'name': 'test', - 'parent': None + "children": [{"id": 2, "name": "test2"}], + "id": 1, + "name": "test", + "parent": None, } diff --git a/tests/test_fastapi/test_excluding_fields.py b/tests/test_fastapi/test_excluding_fields.py index 62a6c228e..e783a313f 100644 --- a/tests/test_fastapi/test_excluding_fields.py +++ b/tests/test_fastapi/test_excluding_fields.py @@ -1,13 +1,13 @@ from typing import List import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL app = FastAPI() @@ -32,9 +32,9 @@ async def shutdown() -> None: class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - metadata = metadata, - database = database, + tablename="categories", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -43,9 +43,9 @@ class Category(ormar.Model): class Item(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "items", - metadata = metadata, - database = database, + tablename="items", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_fastapi/test_extra_ignore_parameter.py b/tests/test_fastapi/test_extra_ignore_parameter.py index 954b541cc..1d1447a99 100644 --- a/tests/test_fastapi/test_extra_ignore_parameter.py +++ b/tests/test_fastapi/test_extra_ignore_parameter.py @@ -1,14 +1,12 @@ -import json - import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient - -import ormar from ormar import Extra + from tests.settings import DATABASE_URL app = FastAPI() @@ -33,9 +31,9 @@ async def shutdown() -> None: class Item(ormar.Model): ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, - extra = Extra.ignore, + database=database, + metadata=metadata, + extra=Extra.ignore, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index 90ea17d9a..ed4bd291f 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -2,6 +2,7 @@ from typing import List, Optional import databases +import ormar import pydantic import pytest import sqlalchemy @@ -9,7 +10,6 @@ from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL app = FastAPI() @@ -111,12 +111,16 @@ async def test_all_endpoints(): item = Item(**response.json()) assert item.pk is not None - response = await client.post("/items/add_category/", json={"item": item.dict(), "category": category}) + response = await client.post( + "/items/add_category/", json={"item": item.dict(), "category": category} + ) item = Item(**response.json()) assert len(item.categories) == 1 assert item.categories[0].name == "test cat" - await client.post("/items/add_category/", json={"item": item.dict(), "category": category2}) + await client.post( + "/items/add_category/", json={"item": item.dict(), "category": category2} + ) response = await client.get("/items/") items = [Item(**item) for item in response.json()] @@ -132,7 +136,9 @@ async def test_all_endpoints(): def test_schema_modification(): schema = Item.model_json_schema() - assert any(x.get("type") == "array" for x in schema["properties"]["categories"]["anyOf"]) + assert any( + x.get("type") == "array" for x in schema["properties"]["categories"]["anyOf"] + ) assert schema["properties"]["categories"]["title"] == "Categories" assert schema["example"] == { "categories": [{"id": 0, "name": "string"}], @@ -151,7 +157,9 @@ def test_schema_modification(): "id": 0, "name": "string", "pydantic_int": 0, - "test_P": [{"a": 0, "b": {"c": "string", "d": "string", "e": "string"}}], + "test_P": [ + {"a": 0, "b": {"c": "string", "d": "string", "e": "string"}} + ], } ], } diff --git a/tests/test_fastapi/test_fastapi_usage.py b/tests/test_fastapi/test_fastapi_usage.py index 7d7ad8466..d276d4c36 100644 --- a/tests/test_fastapi/test_fastapi_usage.py +++ b/tests/test_fastapi/test_fastapi_usage.py @@ -1,13 +1,13 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL app = FastAPI() @@ -18,9 +18,9 @@ class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - metadata = metadata, - database = database, + tablename="categories", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -29,9 +29,9 @@ class Category(ormar.Model): class Item(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "items", - metadata = metadata, - database = database, + tablename="items", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_fastapi/test_inheritance_concrete_fastapi.py b/tests/test_fastapi/test_inheritance_concrete_fastapi.py index 817e306a2..fae0c143c 100644 --- a/tests/test_fastapi/test_inheritance_concrete_fastapi.py +++ b/tests/test_fastapi/test_inheritance_concrete_fastapi.py @@ -9,16 +9,18 @@ from tests.settings import DATABASE_URL from tests.test_inheritance_and_pydantic_generation.test_inheritance_concrete import ( # type: ignore + Bus, + Bus2, Category, - Subject, Person, - Bus, + Subject, Truck, - Bus2, Truck2, - db as database, metadata, ) +from tests.test_inheritance_and_pydantic_generation.test_inheritance_concrete import ( + db as database, +) app = FastAPI() app.state.database = database diff --git a/tests/test_fastapi/test_inheritance_mixins_fastapi.py b/tests/test_fastapi/test_inheritance_mixins_fastapi.py index c1404d6bf..4347718f8 100644 --- a/tests/test_fastapi/test_inheritance_mixins_fastapi.py +++ b/tests/test_fastapi/test_inheritance_mixins_fastapi.py @@ -7,7 +7,14 @@ from httpx import AsyncClient from tests.settings import DATABASE_URL -from tests.test_inheritance_and_pydantic_generation.test_inheritance_mixins import Category, Subject, metadata, db as database # type: ignore +from tests.test_inheritance_and_pydantic_generation.test_inheritance_mixins import ( # type: ignore + Category, + Subject, + metadata, +) +from tests.test_inheritance_and_pydantic_generation.test_inheritance_mixins import ( + db as database, +) app = FastAPI() app.state.database = database diff --git a/tests/test_fastapi/test_json_field_fastapi.py b/tests/test_fastapi/test_json_field_fastapi.py index f168e8c90..744e23638 100644 --- a/tests/test_fastapi/test_json_field_fastapi.py +++ b/tests/test_fastapi/test_json_field_fastapi.py @@ -3,6 +3,7 @@ from typing import List import databases +import ormar import pydantic import pytest import sqlalchemy @@ -10,7 +11,6 @@ from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL app = FastAPI() @@ -39,8 +39,9 @@ async def shutdown() -> None: database=database, ) + class Thing(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "things") + ormar_config = base_ormar_config.copy(tablename="things") id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.Text(default="") @@ -103,7 +104,7 @@ async def test_json_is_required_if_not_nullable(): @pytest.mark.asyncio async def test_json_is_not_required_if_nullable(): class Thing2(ormar.Model): - ormar_config = base_ormar_config.copy( tablename = "things2") + ormar_config = base_ormar_config.copy(tablename="things2") id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.Text(default="") diff --git a/tests/test_fastapi/test_m2m_forwardref.py b/tests/test_fastapi/test_m2m_forwardref.py index 4cfcfaebd..9950890a2 100644 --- a/tests/test_fastapi/test_m2m_forwardref.py +++ b/tests/test_fastapi/test_m2m_forwardref.py @@ -1,15 +1,13 @@ -from typing import List, Optional +from typing import ForwardRef, List, Optional import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI -from typing import ForwardRef -from starlette import status from httpx import AsyncClient - -import ormar +from starlette import status app = FastAPI() from tests.settings import DATABASE_URL @@ -46,8 +44,7 @@ async def shutdown() -> None: # models.py class Country(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "countries") - + ormar_config = base_ormar_config.copy(tablename="countries") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128, unique=True) @@ -65,8 +62,7 @@ class Country(ormar.Model): class City(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "cities") - + ormar_config = base_ormar_config.copy(tablename="cities") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128) diff --git a/tests/test_fastapi/test_more_reallife_fastapi.py b/tests/test_fastapi/test_more_reallife_fastapi.py index 5dec1f6bf..b67dbfa10 100644 --- a/tests/test_fastapi/test_more_reallife_fastapi.py +++ b/tests/test_fastapi/test_more_reallife_fastapi.py @@ -1,13 +1,13 @@ from typing import List, Optional import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL app = FastAPI() @@ -32,9 +32,9 @@ async def shutdown() -> None: class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - metadata = metadata, - database = database, + tablename="categories", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -43,9 +43,9 @@ class Category(ormar.Model): class Item(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "items", - metadata = metadata, - database = database, + tablename="items", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_fastapi/test_nested_saving.py b/tests/test_fastapi/test_nested_saving.py index 81da2763c..952a69056 100644 --- a/tests/test_fastapi/test_nested_saving.py +++ b/tests/test_fastapi/test_nested_saving.py @@ -1,15 +1,14 @@ -import json from typing import Any, Dict, Optional, Set, Type, Union, cast import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient - -import ormar from ormar.queryset.utils import translate_list_to_dict + from tests.settings import DATABASE_URL app = FastAPI() @@ -36,8 +35,8 @@ async def shutdown() -> None: class Department(ormar.Model): ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -46,8 +45,8 @@ class Department(ormar.Model): class Course(ormar.Model): ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -58,8 +57,8 @@ class Course(ormar.Model): class Student(ormar.Model): ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_fastapi/test_recursion_error.py b/tests/test_fastapi/test_recursion_error.py index 6dbbd060c..3fa832ed2 100644 --- a/tests/test_fastapi/test_recursion_error.py +++ b/tests/test_fastapi/test_recursion_error.py @@ -1,9 +1,9 @@ -import json import uuid from datetime import datetime from typing import List import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager @@ -11,7 +11,6 @@ from httpx import AsyncClient from pydantic import BaseModel, Json -import ormar from tests.settings import DATABASE_URL router = FastAPI() @@ -50,9 +49,9 @@ class User(ormar.Model): created_at: datetime = ormar.DateTime(default=datetime.now()) ormar_config = ormar.OrmarConfig( - tablename = "users", - metadata = metadata, - database = database, + tablename="users", + metadata=metadata, + database=database, ) @@ -67,9 +66,9 @@ class UserSession(ormar.Model): created_at: datetime = ormar.DateTime(default=datetime.now()) ormar_config = ormar.OrmarConfig( - tablename = "user_sessions", - metadata = metadata, - database = database, + tablename="user_sessions", + metadata=metadata, + database=database, ) @@ -99,9 +98,9 @@ class Quiz(ormar.Model): questions: Json = ormar.JSON(nullable=False) ormar_config = ormar.OrmarConfig( - tablename = "quiz", - metadata = metadata, - database = database, + tablename="quiz", + metadata=metadata, + database=database, ) diff --git a/tests/test_fastapi/test_relations_with_nested_defaults.py b/tests/test_fastapi/test_relations_with_nested_defaults.py index d8027d411..139eb1958 100644 --- a/tests/test_fastapi/test_relations_with_nested_defaults.py +++ b/tests/test_fastapi/test_relations_with_nested_defaults.py @@ -1,6 +1,7 @@ from typing import Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy @@ -8,7 +9,6 @@ from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -98,24 +98,40 @@ async def test_related_with_defaults(sample_data): client = AsyncClient(app=app, base_url="http://testserver") async with client as client, LifespanManager(app): response = await client.get("/books/1") - assert response.json() == {'author': {'books': [{'author': {'id': 1}, - 'id': 1, - 'title': 'Bug caused by default value', - 'year': 2021}], - 'id': 1}, - 'id': 1, - 'title': 'Bug caused by default value', - 'year': 2021} + assert response.json() == { + "author": { + "books": [ + { + "author": {"id": 1}, + "id": 1, + "title": "Bug caused by default value", + "year": 2021, + } + ], + "id": 1, + }, + "id": 1, + "title": "Bug caused by default value", + "year": 2021, + } response = await client.get("/books_with_author/1") - assert response.json() == {'author': {'books': [{'author': {'id': 1}, - 'id': 1, - 'title': 'Bug caused by default value', - 'year': 2021}], - 'country': {'authors': [{'id': 1}], 'id': 1}, - 'id': 1, - 'name': 'bug', - 'rating': 5}, - 'id': 1, - 'title': 'Bug caused by default value', - 'year': 2021} + assert response.json() == { + "author": { + "books": [ + { + "author": {"id": 1}, + "id": 1, + "title": "Bug caused by default value", + "year": 2021, + } + ], + "country": {"authors": [{"id": 1}], "id": 1}, + "id": 1, + "name": "bug", + "rating": 5, + }, + "id": 1, + "title": "Bug caused by default value", + "year": 2021, + } diff --git a/tests/test_fastapi/test_schema_not_allowed_params.py b/tests/test_fastapi/test_schema_not_allowed_params.py index 3b0ccc4e7..e6123bf5f 100644 --- a/tests/test_fastapi/test_schema_not_allowed_params.py +++ b/tests/test_fastapi/test_schema_not_allowed_params.py @@ -1,7 +1,6 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy DATABASE_URL = "sqlite:///db.sqlite" database = databases.Database(DATABASE_URL) @@ -13,8 +12,9 @@ database=database, ) + class Author(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "authors") + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_fastapi/test_skip_reverse_models.py b/tests/test_fastapi/test_skip_reverse_models.py index e119101b9..e7a8edb2d 100644 --- a/tests/test_fastapi/test_skip_reverse_models.py +++ b/tests/test_fastapi/test_skip_reverse_models.py @@ -1,13 +1,13 @@ from typing import List, Optional import databases +import ormar import pytest import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL app = FastAPI() @@ -47,7 +47,7 @@ class Author(ormar.Model): class Category(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "categories") + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) @@ -80,8 +80,9 @@ async def create_category(category: Category): await category.save_related(follow=True, save_all=True) return category + @app.post("/categories/forbid/", response_model=Category2) -async def create_category(category: Category2): +async def create_category_forbid(category: Category2): await category.save() await category.save_related(follow=True, save_all=True) return category @@ -123,7 +124,7 @@ async def test_queries(): assert response.status_code == 200 response = await client.get("/categories/") assert response.status_code == 200 - assert not "posts" in response.json() + assert "posts" not in response.json() categories = [Category(**x) for x in response.json()] assert categories[0] is not None assert categories[0].name == "Test category2" diff --git a/tests/test_fastapi/test_wekref_exclusion.py b/tests/test_fastapi/test_wekref_exclusion.py index 6f20fa61f..9f304a5c4 100644 --- a/tests/test_fastapi/test_wekref_exclusion.py +++ b/tests/test_fastapi/test_wekref_exclusion.py @@ -2,6 +2,7 @@ from uuid import UUID, uuid4 import databases +import ormar import pydantic import pytest import sqlalchemy @@ -9,7 +10,6 @@ from fastapi import FastAPI from httpx import AsyncClient -import ormar from tests.settings import DATABASE_URL app = FastAPI() @@ -49,7 +49,7 @@ def create_test_database(): class OtherThing(ormar.Model): - ormar_config = base_ormar_config.copy( tablename = "other_things") + ormar_config = base_ormar_config.copy(tablename="other_things") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.Text(default="") @@ -57,7 +57,7 @@ class OtherThing(ormar.Model): class Thing(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "things") + ormar_config = base_ormar_config.copy(tablename="things") id: UUID = ormar.UUID(primary_key=True, default=uuid4) name: str = ormar.Text(default="") diff --git a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py index fdf3bb52a..02bc2d5bf 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py +++ b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py @@ -1,11 +1,11 @@ import datetime import databases +import ormar import pytest import sqlalchemy as sa from sqlalchemy import create_engine -import ormar from tests.settings import DATABASE_URL metadata = sa.MetaData() @@ -15,9 +15,9 @@ class User(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "users", - metadata = metadata, - database = db, + tablename="users", + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -25,18 +25,14 @@ class User(ormar.Model): class RelationalAuditModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract = True - ) + ormar_config = ormar.OrmarConfig(abstract=True) created_by: User = ormar.ForeignKey(User, nullable=False) updated_by: User = ormar.ForeignKey(User, nullable=False) class AuditModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract = True - ) + ormar_config = ormar.OrmarConfig(abstract=True) created_by: str = ormar.String(max_length=100) updated_by: str = ormar.String(max_length=100, default="Sam") @@ -44,9 +40,9 @@ class AuditModel(ormar.Model): class DateFieldsModel(ormar.Model): ormar_config = ormar.OrmarConfig( - abstract = True, - metadata = metadata, - database = db, + abstract=True, + metadata=metadata, + database=db, ) created_date: datetime.datetime = ormar.DateTime( @@ -59,8 +55,8 @@ class DateFieldsModel(ormar.Model): class Category(DateFieldsModel, AuditModel): ormar_config = ormar.OrmarConfig( - tablename = "categories", - exclude_parent_fields = ["updated_by", "updated_date"], + tablename="categories", + exclude_parent_fields=["updated_by", "updated_date"], ) id: int = ormar.Integer(primary_key=True) @@ -70,8 +66,8 @@ class Category(DateFieldsModel, AuditModel): class Item(DateFieldsModel, AuditModel): ormar_config = ormar.OrmarConfig( - tablename = "items", - exclude_parent_fields = ["updated_by", "updated_date"], + tablename="items", + exclude_parent_fields=["updated_by", "updated_date"], ) id: int = ormar.Integer(primary_key=True) @@ -82,8 +78,8 @@ class Item(DateFieldsModel, AuditModel): class Gun(RelationalAuditModel, DateFieldsModel): ormar_config = ormar.OrmarConfig( - tablename = "guns", - exclude_parent_fields = ["updated_by"], + tablename="guns", + exclude_parent_fields=["updated_by"], ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py index fffac628f..e00147c7a 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py +++ b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py @@ -1,13 +1,11 @@ -from typing import List, Optional +from typing import ForwardRef, List, Optional import databases +import ormar import pydantic import sqlalchemy -from typing import ForwardRef - from pydantic_core import PydanticUndefined -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index b53604e2f..7045f1f5d 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -1,20 +1,20 @@ # type: ignore import datetime -from typing import List, Optional from collections import Counter +from typing import List, Optional import databases +import ormar +import ormar.fields.constraints import pydantic import pytest import sqlalchemy as sa -from pydantic import computed_field -from sqlalchemy import create_engine - -import ormar -import ormar.fields.constraints from ormar import ModelDefinitionError from ormar.exceptions import ModelError from ormar.models.metaclass import get_constraint_copy +from pydantic import computed_field +from sqlalchemy import create_engine + from tests.settings import DATABASE_URL metadata = sa.MetaData() @@ -63,13 +63,18 @@ class DateFieldsModel(ormar.Model): ], ) - created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now, name="creation_date") - updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now, name="modification_date") + created_date: datetime.datetime = ormar.DateTime( + default=datetime.datetime.now, name="creation_date" + ) + updated_date: datetime.datetime = ormar.DateTime( + default=datetime.datetime.now, name="modification_date" + ) class Category(DateFieldsModel, AuditModel): ormar_config = ormar.OrmarConfig( - tablename="categories", constraints=[ormar.fields.constraints.UniqueColumns("name", "code")] + tablename="categories", + constraints=[ormar.fields.constraints.UniqueColumns("name", "code")], ) id: int = ormar.Integer(primary_key=True) @@ -161,9 +166,7 @@ class Bus2(Car2): class ImmutablePerson(Person): - model_config = dict( - frozen = True, - validate_assignment = False) + model_config = dict(frozen=True, validate_assignment=False) @pytest.fixture(autouse=True, scope="module") @@ -202,8 +205,13 @@ class RedefinedField(DateFieldsModel): changed_field = RedefinedField.ormar_config.model_fields["created_date"] assert changed_field.ormar_default is None assert changed_field.get_alias() == "creation_date" - assert any(x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns) - assert isinstance(RedefinedField.ormar_config.table.columns["creation_date"].type, sa.sql.sqltypes.String) + assert any( + x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns + ) + assert isinstance( + RedefinedField.ormar_config.table.columns["creation_date"].type, + sa.sql.sqltypes.String, + ) def test_model_subclassing_that_redefines_constraints_column_names(): @@ -256,25 +264,38 @@ def round_date_to_seconds( async def test_fields_inherited_from_mixin(): async with db: async with db.transaction(force_rollback=True): - cat = await Category(name="Foo", code=123, created_by="Sam", updated_by="Max").save() + cat = await Category( + name="Foo", code=123, created_by="Sam", updated_by="Max" + ).save() sub = await Subject(name="Bar", category=cat).save() mixin_columns = ["created_date", "updated_date"] mixin_db_columns = ["creation_date", "modification_date"] mixin2_columns = ["created_by", "updated_by"] - assert all(field in Category.ormar_config.model_fields for field in mixin_columns) + assert all( + field in Category.ormar_config.model_fields for field in mixin_columns + ) assert cat.created_date is not None assert cat.updated_date is not None - assert all(field in Subject.ormar_config.model_fields for field in mixin_columns) + assert all( + field in Subject.ormar_config.model_fields for field in mixin_columns + ) assert sub.created_date is not None assert sub.updated_date is not None - assert all(field in Category.ormar_config.model_fields for field in mixin2_columns) - assert all(field not in Subject.ormar_config.model_fields for field in mixin2_columns) + assert all( + field in Category.ormar_config.model_fields for field in mixin2_columns + ) + assert all( + field not in Subject.ormar_config.model_fields + for field in mixin2_columns + ) inspector = sa.inspect(engine) assert "categories" in inspector.get_table_names() table_columns = [x.get("name") for x in inspector.get_columns("categories")] - assert all(col in table_columns for col in mixin_db_columns) # + mixin2_columns) + assert all( + col in table_columns for col in mixin_db_columns + ) # + mixin2_columns) assert "subjects" in inspector.get_table_names() table_columns = [x.get("name") for x in inspector.get_columns("subjects")] @@ -286,9 +307,13 @@ async def test_fields_inherited_from_mixin(): .exclude_fields("updated_date") .get() ) - assert round_date_to_seconds(sub2.created_date) == round_date_to_seconds(sub.created_date) + assert round_date_to_seconds(sub2.created_date) == round_date_to_seconds( + sub.created_date + ) assert sub2.category.updated_date is not None - assert round_date_to_seconds(sub2.category.created_date) == round_date_to_seconds(cat.created_date) + assert round_date_to_seconds( + sub2.category.created_date + ) == round_date_to_seconds(cat.created_date) assert sub2.updated_date is None assert sub2.category.created_by == "Sam" assert sub2.category.updated_by == cat.updated_by @@ -299,9 +324,13 @@ async def test_fields_inherited_from_mixin(): .exclude_fields({"updated_date": ..., "category": {"updated_date"}}) .get() ) - assert round_date_to_seconds(sub3.created_date) == round_date_to_seconds(sub.created_date) + assert round_date_to_seconds(sub3.created_date) == round_date_to_seconds( + sub.created_date + ) assert sub3.category.updated_date is None - assert round_date_to_seconds(sub3.category.created_date) == round_date_to_seconds(cat.created_date) + assert round_date_to_seconds( + sub3.category.created_date + ) == round_date_to_seconds(cat.created_date) assert sub3.updated_date is None assert sub3.category.created_by == "Sam" assert sub3.category.updated_by == cat.updated_by @@ -313,7 +342,9 @@ async def test_inheritance_with_relation(): async with db.transaction(force_rollback=True): sam = await Person(name="Sam").save() joe = await Person(name="Joe").save() - await Truck(name="Shelby wanna be", max_capacity=1400, owner=sam, co_owner=joe).save() + await Truck( + name="Shelby wanna be", max_capacity=1400, owner=sam, co_owner=joe + ).save() await Bus(name="Unicorn", max_persons=50, owner=sam, co_owner=joe).save() shelby = await Truck.objects.select_related(["owner", "co_owner"]).get() @@ -328,7 +359,9 @@ async def test_inheritance_with_relation(): assert unicorn.co_owner.name == "Joe" assert unicorn.max_persons == 50 - joe_check = await Person.objects.select_related(["coowned_trucks", "coowned_buses"]).get(name="Joe") + joe_check = await Person.objects.select_related( + ["coowned_trucks", "coowned_buses"] + ).get(name="Joe") assert joe_check.pk == joe.pk assert joe_check.coowned_trucks[0] == shelby assert joe_check.coowned_trucks[0].created_date is not None @@ -359,7 +392,9 @@ async def test_inheritance_with_multi_relation(): sam = await Person(name="Sam").save() joe = await Person(name="Joe").save() alex = await Person(name="Alex").save() - truck = await Truck2(name="Shelby wanna be 2", max_capacity=1400, owner=sam).save() + truck = await Truck2( + name="Shelby wanna be 2", max_capacity=1400, owner=sam + ).save() await truck.co_owners.add(joe) await truck.co_owners.add(alex) @@ -377,26 +412,38 @@ async def test_inheritance_with_multi_relation(): assert len(shelby.co_owners) == 2 assert shelby.max_capacity == 1400 - unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).get(name="Unicorn 2") + unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).get( + name="Unicorn 2" + ) assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert unicorn.co_owners[0].name == "Joe" assert len(unicorn.co_owners) == 2 assert unicorn.max_persons == 50 - unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).order_by("-co_owners__name").get() + unicorn = ( + await Bus2.objects.select_related(["owner", "co_owners"]) + .order_by("-co_owners__name") + .get() + ) assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert len(unicorn.co_owners) == 2 assert unicorn.co_owners[0].name == "Joe" - unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).order_by("co_owners__name").get() + unicorn = ( + await Bus2.objects.select_related(["owner", "co_owners"]) + .order_by("co_owners__name") + .get() + ) assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert len(unicorn.co_owners) == 2 assert unicorn.co_owners[0].name == "Alex" - joe_check = await Person.objects.select_related(["coowned_trucks2", "coowned_buses2"]).get(name="Joe") + joe_check = await Person.objects.select_related( + ["coowned_trucks2", "coowned_buses2"] + ).get(name="Joe") assert joe_check.pk == joe.pk assert joe_check.coowned_trucks2[0] == shelby assert joe_check.coowned_trucks2[0].created_date is not None @@ -423,14 +470,22 @@ async def test_inheritance_with_multi_relation(): await shelby.co_owners.remove(alex) await Truck2.objects.delete(name="Shelby wanna be 2") - unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).filter(co_owners__name="Joe").get() + unicorn = ( + await Bus2.objects.select_related(["owner", "co_owners"]) + .filter(co_owners__name="Joe") + .get() + ) assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert unicorn.co_owners[0].name == "Joe" assert len(unicorn.co_owners) == 1 assert unicorn.max_persons == 50 - unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).exclude(co_owners__name="Joe").get() + unicorn = ( + await Bus2.objects.select_related(["owner", "co_owners"]) + .exclude(co_owners__name="Joe") + .get() + ) assert unicorn.name == "Unicorn 2" assert unicorn.owner.name == "Sam" assert unicorn.co_owners[0].name == "Alex" diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py index d21ec0bce..c643f44ef 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py @@ -3,11 +3,11 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy as sa from sqlalchemy import create_engine -import ormar from tests.settings import DATABASE_URL metadata = sa.MetaData() @@ -27,9 +27,9 @@ class DateFieldsMixins: class Category(ormar.Model, DateFieldsMixins, AuditMixin): ormar_config = ormar.OrmarConfig( - tablename = "categories", - metadata = metadata, - database = db, + tablename="categories", + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -39,9 +39,9 @@ class Category(ormar.Model, DateFieldsMixins, AuditMixin): class Subject(ormar.Model, DateFieldsMixins): ormar_config = ormar.OrmarConfig( - tablename = "subjects", - metadata = metadata, - database = db, + tablename="subjects", + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -59,48 +59,59 @@ def create_test_database(): def test_field_redefining(): class RedefinedField(ormar.Model, DateFieldsMixins): ormar_config = ormar.OrmarConfig( - tablename = "redefined", - metadata = metadata, - database = db, + tablename="redefined", + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) created_date: datetime.datetime = ormar.DateTime(name="creation_date") - assert RedefinedField.ormar_config.model_fields["created_date"].ormar_default is None assert ( - RedefinedField.ormar_config.model_fields["created_date"].get_alias() == "creation_date" + RedefinedField.ormar_config.model_fields["created_date"].ormar_default is None + ) + assert ( + RedefinedField.ormar_config.model_fields["created_date"].get_alias() + == "creation_date" + ) + assert any( + x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns ) - assert any(x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns) def test_field_redefining_in_second_raises_error(): class OkField(ormar.Model, DateFieldsMixins): # pragma: no cover ormar_config = ormar.OrmarConfig( - tablename = "oks", - metadata = metadata, - database = db, + tablename="oks", + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) class RedefinedField2(ormar.Model, DateFieldsMixins): ormar_config = ormar.OrmarConfig( - tablename = "redefines2", - metadata = metadata, - database = db, + tablename="redefines2", + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) created_date: str = ormar.String(max_length=200, name="creation_date") - assert RedefinedField2.ormar_config.model_fields["created_date"].ormar_default is None assert ( - RedefinedField2.ormar_config.model_fields["created_date"].get_alias() == "creation_date" + RedefinedField2.ormar_config.model_fields["created_date"].ormar_default is None + ) + assert ( + RedefinedField2.ormar_config.model_fields["created_date"].get_alias() + == "creation_date" + ) + assert any( + x.name == "creation_date" for x in RedefinedField2.ormar_config.table.columns ) - assert any(x.name == "creation_date" for x in RedefinedField2.ormar_config.table.columns) assert isinstance( - RedefinedField2.ormar_config.table.columns["creation_date"].type, sa.sql.sqltypes.String + RedefinedField2.ormar_config.table.columns["creation_date"].type, + sa.sql.sqltypes.String, ) @@ -122,16 +133,23 @@ async def test_fields_inherited_from_mixin(): sub = await Subject(name="Bar", category=cat).save() mixin_columns = ["created_date", "updated_date"] mixin2_columns = ["created_by", "updated_by"] - assert all(field in Category.ormar_config.model_fields for field in mixin_columns) + assert all( + field in Category.ormar_config.model_fields for field in mixin_columns + ) assert cat.created_date is not None assert cat.updated_date is not None - assert all(field in Subject.ormar_config.model_fields for field in mixin_columns) + assert all( + field in Subject.ormar_config.model_fields for field in mixin_columns + ) assert sub.created_date is not None assert sub.updated_date is not None - assert all(field in Category.ormar_config.model_fields for field in mixin2_columns) assert all( - field not in Subject.ormar_config.model_fields for field in mixin2_columns + field in Category.ormar_config.model_fields for field in mixin2_columns + ) + assert all( + field not in Subject.ormar_config.model_fields + for field in mixin2_columns ) inspector = sa.inspect(engine) diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py index e52673327..11740b0de 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py @@ -1,10 +1,10 @@ import databases +import ormar import pytest import sqlalchemy import sqlalchemy as sa from pydantic import computed_field -import ormar from tests.settings import DATABASE_URL metadata = sa.MetaData() @@ -12,8 +12,7 @@ class BaseFoo(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract = True) + ormar_config = ormar.OrmarConfig(abstract=True) name: str = ormar.String(max_length=100) @@ -24,8 +23,8 @@ def prefixed_name(self) -> str: class Foo(BaseFoo): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, + metadata=metadata, + database=database, ) @computed_field @@ -37,8 +36,8 @@ def double_prefixed_name(self) -> str: class Bar(BaseFoo): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, + metadata=metadata, + database=database, ) @computed_field diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py index 9c487bfae..c1b405514 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py @@ -2,10 +2,10 @@ import uuid import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() diff --git a/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py b/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py index 7258579ea..a038fab5c 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py @@ -1,10 +1,10 @@ import datetime import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() @@ -13,9 +13,9 @@ class TableBase(ormar.Model): ormar_config = ormar.OrmarConfig( - abstract = True, - metadata = metadata, - database = database, + abstract=True, + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -28,9 +28,7 @@ class TableBase(ormar.Model): class NationBase(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract = True - ) + ormar_config = ormar.OrmarConfig(abstract=True) name: str = ormar.String(max_length=50) alpha2_code: str = ormar.String(max_length=2) diff --git a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py index bee065a8e..e0939f2c1 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py @@ -1,7 +1,7 @@ import databases +import ormar import sqlalchemy -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() diff --git a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py index 25b16fad8..fe57cdec1 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py +++ b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py @@ -1,8 +1,8 @@ import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() @@ -17,8 +17,8 @@ class NewTestModel(ormar.Model): ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, + database=database, + metadata=metadata, ) a: int = ormar.Integer(primary_key=True) diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py index 9e1aac75d..b09e2740a 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py @@ -1,11 +1,11 @@ import enum import databases +import ormar import pytest import sqlalchemy from pydantic import ValidationError, field_validator -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py index 4c3344085..d8d4ee97e 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py @@ -1,13 +1,12 @@ import enum import databases +import ormar import pydantic import pytest import sqlalchemy from pydantic import ValidationError - -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() diff --git a/tests/test_meta_constraints/test_check_constraints.py b/tests/test_meta_constraints/test_check_constraints.py index 66119a1ec..c55a4d9f5 100644 --- a/tests/test_meta_constraints/test_check_constraints.py +++ b/tests/test_meta_constraints/test_check_constraints.py @@ -2,10 +2,10 @@ import asyncpg # type: ignore import databases +import ormar.fields.constraints import pytest import sqlalchemy -import ormar.fields.constraints from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -14,12 +14,13 @@ class Product(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "products", - metadata = metadata, - database = database, - constraints = [ + tablename="products", + metadata=metadata, + database=database, + constraints=[ ormar.fields.constraints.CheckColumns("inventory > buffer"), - ]) + ], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_meta_constraints/test_index_constraints.py b/tests/test_meta_constraints/test_index_constraints.py index 217ca06a0..056b90204 100644 --- a/tests/test_meta_constraints/test_index_constraints.py +++ b/tests/test_meta_constraints/test_index_constraints.py @@ -1,9 +1,8 @@ -import asyncpg # type: ignore import databases +import ormar.fields.constraints import pytest import sqlalchemy -import ormar.fields.constraints from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -12,13 +11,13 @@ class Product(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "products", - metadata = metadata, - database = database, - constraints = [ + tablename="products", + metadata=metadata, + database=database, + constraints=[ ormar.fields.constraints.IndexColumns("company", "name", name="my_index"), ormar.fields.constraints.IndexColumns("location", "company_type"), - ] + ], ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_meta_constraints/test_unique_constraints.py b/tests/test_meta_constraints/test_unique_constraints.py index 3d0536634..91623c935 100644 --- a/tests/test_meta_constraints/test_unique_constraints.py +++ b/tests/test_meta_constraints/test_unique_constraints.py @@ -2,11 +2,11 @@ import asyncpg # type: ignore import databases +import ormar.fields.constraints import pymysql import pytest import sqlalchemy -import ormar.fields.constraints from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -15,10 +15,10 @@ class Product(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "products", - metadata = metadata, - database = database, - constraints = [ormar.fields.constraints.UniqueColumns("name", "company")], + tablename="products", + metadata=metadata, + database=database, + constraints=[ormar.fields.constraints.UniqueColumns("name", "company")], ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_model_definition/pks_and_fks/test_non_integer_pkey.py b/tests/test_model_definition/pks_and_fks/test_non_integer_pkey.py index 4485f51fc..4ae7855dd 100644 --- a/tests/test_model_definition/pks_and_fks/test_non_integer_pkey.py +++ b/tests/test_model_definition/pks_and_fks/test_non_integer_pkey.py @@ -1,10 +1,10 @@ import random import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/pks_and_fks/test_saving_string_pks.py b/tests/test_model_definition/pks_and_fks/test_saving_string_pks.py index bd4dadcff..8c6fedd8f 100644 --- a/tests/test_model_definition/pks_and_fks/test_saving_string_pks.py +++ b/tests/test_model_definition/pks_and_fks/test_saving_string_pks.py @@ -2,13 +2,13 @@ from string import ascii_uppercase import databases +import ormar import pytest import pytest_asyncio import sqlalchemy +from ormar import Float, String from sqlalchemy import create_engine -import ormar -from ormar import Float, String from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/pks_and_fks/test_uuid_fks.py b/tests/test_model_definition/pks_and_fks/test_uuid_fks.py index 9aacf1ae8..5444c7ec6 100644 --- a/tests/test_model_definition/pks_and_fks/test_uuid_fks.py +++ b/tests/test_model_definition/pks_and_fks/test_uuid_fks.py @@ -1,11 +1,11 @@ import uuid import databases +import ormar import pytest import sqlalchemy from sqlalchemy import create_engine -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() @@ -14,9 +14,9 @@ class User(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "user", - metadata = metadata, - database = db, + tablename="user", + metadata=metadata, + database=db, ) id: uuid.UUID = ormar.UUID( @@ -31,9 +31,9 @@ class User(ormar.Model): class Token(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "token", - metadata = metadata, - database = db, + tablename="token", + metadata=metadata, + database=db, ) id = ormar.Integer(primary_key=True) diff --git a/tests/test_model_definition/test_aliases.py b/tests/test_model_definition/test_aliases.py index 9f131dd42..8d01616c9 100644 --- a/tests/test_model_definition/test_aliases.py +++ b/tests/test_model_definition/test_aliases.py @@ -1,10 +1,10 @@ from typing import List, Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -12,7 +12,6 @@ class Child(ormar.Model): - ormar_config = ormar.OrmarConfig( tablename="children", metadata=metadata, @@ -26,7 +25,6 @@ class Child(ormar.Model): class Artist(ormar.Model): - ormar_config = ormar.OrmarConfig( tablename="artists", metadata=metadata, diff --git a/tests/test_model_definition/test_columns.py b/tests/test_model_definition/test_columns.py index 25eeb4135..b426c4ffd 100644 --- a/tests/test_model_definition/test_columns.py +++ b/tests/test_model_definition/test_columns.py @@ -2,12 +2,12 @@ from enum import Enum import databases +import ormar import pydantic import pytest import sqlalchemy - -import ormar from ormar import ModelDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_create_uses_init_for_consistency.py b/tests/test_model_definition/test_create_uses_init_for_consistency.py index 02d431d9f..6142bfce9 100644 --- a/tests/test_model_definition/test_create_uses_init_for_consistency.py +++ b/tests/test_model_definition/test_create_uses_init_for_consistency.py @@ -2,11 +2,11 @@ from typing import ClassVar import databases +import ormar import pytest import sqlalchemy -from pydantic import model_validator, root_validator +from pydantic import model_validator -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_dates_with_timezone.py b/tests/test_model_definition/test_dates_with_timezone.py index 670e8d17a..a524938c9 100644 --- a/tests/test_model_definition/test_dates_with_timezone.py +++ b/tests/test_model_definition/test_dates_with_timezone.py @@ -1,11 +1,10 @@ -from datetime import timezone, timedelta, datetime, date, time +from datetime import date, datetime, time, timedelta, timezone import databases +import ormar import pytest import sqlalchemy -import ormar - from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_equality_and_hash.py b/tests/test_model_definition/test_equality_and_hash.py index e72082fe1..e8b52a61b 100644 --- a/tests/test_model_definition/test_equality_and_hash.py +++ b/tests/test_model_definition/test_equality_and_hash.py @@ -1,9 +1,9 @@ # type: ignore import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_extra_ignore_parameter.py b/tests/test_model_definition/test_extra_ignore_parameter.py index a15c96f98..9726db449 100644 --- a/tests/test_model_definition/test_extra_ignore_parameter.py +++ b/tests/test_model_definition/test_extra_ignore_parameter.py @@ -1,8 +1,8 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy from ormar import Extra + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_fields_access.py b/tests/test_model_definition/test_fields_access.py index b744a605e..a4c34e534 100644 --- a/tests/test_model_definition/test_fields_access.py +++ b/tests/test_model_definition/test_fields_access.py @@ -1,9 +1,9 @@ import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar import BaseField + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -17,7 +17,6 @@ class PriceList(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="price_lists") id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py b/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py index 354e02b6c..9df1ef505 100644 --- a/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py +++ b/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py @@ -1,11 +1,11 @@ import uuid -from typing import List, Optional +from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_iterate.py b/tests/test_model_definition/test_iterate.py index 884650481..2dcad639e 100644 --- a/tests/test_model_definition/test_iterate.py +++ b/tests/test_model_definition/test_iterate.py @@ -1,10 +1,11 @@ import uuid + import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar.exceptions import QueryDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_model_construct.py b/tests/test_model_definition/test_model_construct.py index e51ee13fe..f34bd3f45 100644 --- a/tests/test_model_definition/test_model_construct.py +++ b/tests/test_model_definition/test_model_construct.py @@ -1,10 +1,10 @@ from typing import List import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -68,7 +68,7 @@ def create_test_database(): async def test_construct_with_empty_relation(): async with database: async with database.transaction(force_rollback=True): - hq = await HQ.objects.create(name="Main") + await HQ.objects.create(name="Main") comp = Company(name="Banzai", hq=None, founded=1988) comp2 = Company.construct(**dict(name="Banzai", hq=None, founded=1988)) assert comp.dict() == comp2.dict() diff --git a/tests/test_model_definition/test_model_definition.py b/tests/test_model_definition/test_model_definition.py index 4a8c68c22..82ce8c96b 100644 --- a/tests/test_model_definition/test_model_definition.py +++ b/tests/test_model_definition/test_model_definition.py @@ -1,18 +1,16 @@ # type: ignore -import asyncio import datetime import decimal +import typing import databases +import ormar import pydantic import pytest -import pytest_asyncio import sqlalchemy -import typing - -import ormar from ormar.exceptions import ModelDefinitionError from ormar.models import Model + from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index 5a02bb02a..a7f664b38 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -3,16 +3,15 @@ import datetime import os import uuid -from enum import Enum, Flag -from typing import List +from enum import Enum import databases +import ormar import pydantic import pytest import sqlalchemy - -import ormar from ormar.exceptions import ModelError, NoMatch, QueryDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_models_are_pickable.py b/tests/test_model_definition/test_models_are_pickable.py index 61bd941ab..42d7adcbc 100644 --- a/tests/test_model_definition/test_models_are_pickable.py +++ b/tests/test_model_definition/test_models_are_pickable.py @@ -2,10 +2,10 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_overwriting_pydantic_field_type.py b/tests/test_model_definition/test_overwriting_pydantic_field_type.py index 1c5824651..92d97acee 100644 --- a/tests/test_model_definition/test_overwriting_pydantic_field_type.py +++ b/tests/test_model_definition/test_overwriting_pydantic_field_type.py @@ -1,11 +1,11 @@ from typing import Dict, Optional import databases +import ormar import pytest import sqlalchemy from pydantic import Json, PositiveInt, ValidationError -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_overwriting_sql_nullable.py b/tests/test_model_definition/test_overwriting_sql_nullable.py index 71c57c2b5..08b103556 100644 --- a/tests/test_model_definition/test_overwriting_sql_nullable.py +++ b/tests/test_model_definition/test_overwriting_sql_nullable.py @@ -3,13 +3,12 @@ import asyncpg import databases +import ormar import pymysql +import pytest import sqlalchemy from sqlalchemy import create_engine, text -import ormar -import pytest - from tests.settings import DATABASE_URL db = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_pk_field_is_always_not_null.py b/tests/test_model_definition/test_pk_field_is_always_not_null.py index f32eb0c74..c4a37e6e4 100644 --- a/tests/test_model_definition/test_pk_field_is_always_not_null.py +++ b/tests/test_model_definition/test_pk_field_is_always_not_null.py @@ -1,7 +1,7 @@ import databases +import ormar import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) diff --git a/tests/test_model_definition/test_properties.py b/tests/test_model_definition/test_properties.py index 98a416fab..293830a3e 100644 --- a/tests/test_model_definition/test_properties.py +++ b/tests/test_model_definition/test_properties.py @@ -1,11 +1,10 @@ # type: ignore import databases +import ormar import pytest import sqlalchemy from pydantic import PydanticUserError, computed_field -import ormar -from ormar import ModelDefinitionError from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_pydantic_fields.py b/tests/test_model_definition/test_pydantic_fields.py index 775ae3b4a..4817b8a3e 100644 --- a/tests/test_model_definition/test_pydantic_fields.py +++ b/tests/test_model_definition/test_pydantic_fields.py @@ -2,11 +2,11 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy from pydantic import BaseModel, Field, HttpUrl, PaymentCardNumber -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) diff --git a/tests/test_model_definition/test_pydantic_only_fields.py b/tests/test_model_definition/test_pydantic_only_fields.py index ffd0a64a8..bc43249a3 100644 --- a/tests/test_model_definition/test_pydantic_only_fields.py +++ b/tests/test_model_definition/test_pydantic_only_fields.py @@ -1,11 +1,11 @@ import datetime import databases +import ormar import pytest import sqlalchemy from pydantic import computed_field -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_pydantic_private_attributes.py b/tests/test_model_definition/test_pydantic_private_attributes.py index c4a066ff5..c990dcf74 100644 --- a/tests/test_model_definition/test_pydantic_private_attributes.py +++ b/tests/test_model_definition/test_pydantic_private_attributes.py @@ -1,10 +1,10 @@ from typing import List import databases +import ormar import sqlalchemy from pydantic import PrivateAttr -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_save_status.py b/tests/test_model_definition/test_save_status.py index 7efd45491..224040c02 100644 --- a/tests/test_model_definition/test_save_status.py +++ b/tests/test_model_definition/test_save_status.py @@ -1,11 +1,11 @@ from typing import List import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar.exceptions import ModelPersistenceError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_saving_nullable_fields.py b/tests/test_model_definition/test_saving_nullable_fields.py index 09618eb1b..18cb0ef29 100644 --- a/tests/test_model_definition/test_saving_nullable_fields.py +++ b/tests/test_model_definition/test_saving_nullable_fields.py @@ -1,11 +1,10 @@ from typing import Optional import databases -import sqlalchemy -from sqlalchemy import create_engine - import ormar import pytest +import sqlalchemy +from sqlalchemy import create_engine from tests.settings import DATABASE_URL diff --git a/tests/test_model_definition/test_server_default.py b/tests/test_model_definition/test_server_default.py index 877d9f29f..45e8bf6ed 100644 --- a/tests/test_model_definition/test_server_default.py +++ b/tests/test_model_definition/test_server_default.py @@ -1,13 +1,12 @@ -import asyncio import time from datetime import datetime import databases +import ormar import pytest import sqlalchemy from sqlalchemy import func, text -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_definition/test_setting_comments_in_db.py b/tests/test_model_definition/test_setting_comments_in_db.py index 4c1f08a0f..213c0cf7f 100644 --- a/tests/test_model_definition/test_setting_comments_in_db.py +++ b/tests/test_model_definition/test_setting_comments_in_db.py @@ -1,9 +1,9 @@ import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar.models import Model + from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() diff --git a/tests/test_model_methods/test_excludes_in_load_all.py b/tests/test_model_methods/test_excludes_in_load_all.py index ad11e3267..62238ca5e 100644 --- a/tests/test_model_methods/test_excludes_in_load_all.py +++ b/tests/test_model_methods/test_excludes_in_load_all.py @@ -1,11 +1,9 @@ -import asyncio import uuid -import pytest - +import databases import ormar +import pytest import sqlalchemy -import databases from tests.settings import DATABASE_URL @@ -22,13 +20,17 @@ class JimmyUser(ormar.Model): ormar_config = base_ormar_config.copy(tablename="jimmy_users") - id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4(), uuid_format="string") + id: uuid.UUID = ormar.UUID( + primary_key=True, default=uuid.uuid4(), uuid_format="string" + ) class JimmyProfile(ormar.Model): ormar_config = base_ormar_config.copy(tablename="jimmy_profiles") - id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4(), uuid_format="string") + id: uuid.UUID = ormar.UUID( + primary_key=True, default=uuid.uuid4(), uuid_format="string" + ) name = ormar.String(max_length=42, default="JimmyProfile") user: JimmyUser = ormar.ForeignKey(to=JimmyUser) @@ -36,7 +38,9 @@ class JimmyProfile(ormar.Model): class JimmyAccount(ormar.Model): ormar_config = base_ormar_config.copy(tablename="jimmy_accounts") - id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4(), uuid_format="string") + id: uuid.UUID = ormar.UUID( + primary_key=True, default=uuid.uuid4(), uuid_format="string" + ) name = ormar.String(max_length=42, default="JimmyAccount") user: JimmyUser = ormar.ForeignKey(to=JimmyUser) diff --git a/tests/test_model_methods/test_load_all.py b/tests/test_model_methods/test_load_all.py index 9eb336618..4a9f9086f 100644 --- a/tests/test_model_methods/test_load_all.py +++ b/tests/test_model_methods/test_load_all.py @@ -1,10 +1,10 @@ from typing import List import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -18,7 +18,7 @@ class Language(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "languages") + ormar_config = base_ormar_config.copy(tablename="languages") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -26,7 +26,7 @@ class Language(ormar.Model): class CringeLevel(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "levels") + ormar_config = base_ormar_config.copy(tablename="levels") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -34,7 +34,7 @@ class CringeLevel(ormar.Model): class NickName(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "nicks") + ormar_config = base_ormar_config.copy(tablename="nicks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -43,7 +43,7 @@ class NickName(ormar.Model): class HQ(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "hqs") + ormar_config = base_ormar_config.copy(tablename="hqs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -51,7 +51,7 @@ class HQ(ormar.Model): class Company(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "companies") + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") diff --git a/tests/test_model_methods/test_populate_default_values.py b/tests/test_model_methods/test_populate_default_values.py index 3bdc6b3ab..92de8528d 100644 --- a/tests/test_model_methods/test_populate_default_values.py +++ b/tests/test_model_methods/test_populate_default_values.py @@ -1,9 +1,8 @@ import databases -import pytest +import ormar import sqlalchemy from sqlalchemy import text -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_model_methods/test_save_related.py b/tests/test_model_methods/test_save_related.py index 3236cac77..c10f9d3e4 100644 --- a/tests/test_model_methods/test_save_related.py +++ b/tests/test_model_methods/test_save_related.py @@ -1,10 +1,10 @@ from typing import List import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -194,8 +194,12 @@ async def test_saving_nested(): async with database.transaction(force_rollback=True): level = await CringeLevel.objects.create(name="High") level2 = await CringeLevel.objects.create(name="Low") - nick1 = await NickName.objects.create(name="BazingaO", is_lame=False, level=level) - nick2 = await NickName.objects.create(name="Bazinga20", is_lame=True, level=level2) + nick1 = await NickName.objects.create( + name="BazingaO", is_lame=False, level=level + ) + nick2 = await NickName.objects.create( + name="Bazinga20", is_lame=True, level=level2 + ) hq = await HQ.objects.create(name="Main") assert hq.saved diff --git a/tests/test_model_methods/test_save_related_from_dict.py b/tests/test_model_methods/test_save_related_from_dict.py index e76dde3dd..46013071f 100644 --- a/tests/test_model_methods/test_save_related_from_dict.py +++ b/tests/test_model_methods/test_save_related_from_dict.py @@ -1,10 +1,10 @@ from typing import List import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -246,7 +246,9 @@ async def test_saving_nested_with_m2m_and_rev_fk_and_through(): count = await company.save_related(follow=True, save_all=True) assert count == 6 - company_check = await Company.objects.select_related("hq__nicks__level").get() + company_check = await Company.objects.select_related( + "hq__nicks__level" + ).get() assert company_check.pk is not None assert company_check.name == "Main" assert company_check.hq.name == "Yoko" diff --git a/tests/test_model_methods/test_save_related_uuid.py b/tests/test_model_methods/test_save_related_uuid.py index 3dbb16d87..ad1568f19 100644 --- a/tests/test_model_methods/test_save_related_uuid.py +++ b/tests/test_model_methods/test_save_related_uuid.py @@ -2,10 +2,10 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -75,7 +75,9 @@ async def test_uuid_pk_in_save_related(): department = Department(**to_save) await department.save_related(follow=True, save_all=True) department_check = ( - await Department.objects.select_all(follow=True).order_by(Department.courses.students.name.asc()).get() + await Department.objects.select_all(follow=True) + .order_by(Department.courses.students.name.asc()) + .get() ) to_exclude = { "id": ..., diff --git a/tests/test_model_methods/test_update.py b/tests/test_model_methods/test_update.py index 0b6fd635f..22a81c677 100644 --- a/tests/test_model_methods/test_update.py +++ b/tests/test_model_methods/test_update.py @@ -1,10 +1,10 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -52,7 +52,9 @@ async def test_updating_selected_columns(): director1 = await Director(name="Peter", last_name="Jackson").save() director2 = await Director(name="James", last_name="Cameron").save() - lotr = await Movie(name="LOTR", year=2001, director=director1, profit=1.140).save() + lotr = await Movie( + name="LOTR", year=2001, director=director1, profit=1.140 + ).save() lotr.name = "Lord of The Rings" lotr.year = 2003 @@ -84,7 +86,9 @@ async def test_updating_selected_columns(): async def test_not_passing_columns_or_empty_list_saves_all(): async with database: director = await Director(name="James", last_name="Cameron").save() - terminator = await Movie(name="Terminator", year=1984, director=director, profit=0.078).save() + terminator = await Movie( + name="Terminator", year=1984, director=director, profit=0.078 + ).save() terminator.name = "Terminator 2" terminator.year = 1991 diff --git a/tests/test_model_methods/test_upsert.py b/tests/test_model_methods/test_upsert.py index 939c10df7..ad216862a 100644 --- a/tests/test_model_methods/test_upsert.py +++ b/tests/test_model_methods/test_upsert.py @@ -1,10 +1,10 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -51,14 +51,16 @@ async def test_updating_selected_columns(): async with database: director1 = await Director(name="Peter", last_name="Jackson").save() - await Movie(id=1, name="Lord of The Rings", year=2003, director=director1, profit=1.212).upsert() + await Movie( + id=1, name="Lord of The Rings", year=2003, director=director1, profit=1.212 + ).upsert() with pytest.raises(ormar.NoMatch): await Movie.objects.get() - await Movie(id=1, name="Lord of The Rings", year=2003, director=director1, profit=1.212).upsert( - __force_save__=True - ) + await Movie( + id=1, name="Lord of The Rings", year=2003, director=director1, profit=1.212 + ).upsert(__force_save__=True) lotr = await Movie.objects.get() assert lotr.year == 2003 assert lotr.name == "Lord of The Rings" diff --git a/tests/test_ordering/test_default_model_order.py b/tests/test_ordering/test_default_model_order.py index 2bde5f2ff..90f400649 100644 --- a/tests/test_ordering/test_default_model_order.py +++ b/tests/test_ordering/test_default_model_order.py @@ -1,11 +1,11 @@ from typing import Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -26,7 +26,9 @@ class Author(ormar.Model): class Book(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="books", order_by=["year", "-ranking"]) + ormar_config = base_ormar_config.copy( + tablename="books", order_by=["year", "-ranking"] + ) id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -77,8 +79,12 @@ async def test_default_orders_is_applied(): async def test_default_orders_is_applied_on_related(): async with database: tolkien = await Author(name="J.R.R. Tolkien").save() - silmarillion = await Book(author=tolkien, title="The Silmarillion", year=1977).save() - lotr = await Book(author=tolkien, title="The Lord of the Rings", year=1955).save() + silmarillion = await Book( + author=tolkien, title="The Silmarillion", year=1977 + ).save() + lotr = await Book( + author=tolkien, title="The Lord of the Rings", year=1955 + ).save() hobbit = await Book(author=tolkien, title="The Hobbit", year=1933).save() await tolkien.books.all() @@ -96,9 +102,13 @@ async def test_default_orders_is_applied_on_related(): async def test_default_orders_is_applied_on_related_two_fields(): async with database: sanders = await Author(name="Brandon Sanderson").save() - twok = await Book(author=sanders, title="The Way of Kings", year=2010, ranking=10).save() + twok = await Book( + author=sanders, title="The Way of Kings", year=2010, ranking=10 + ).save() bret = await Author(name="Peter V. Bret").save() - tds = await Book(author=bret, title="The Desert Spear", year=2010, ranking=9).save() + tds = await Book( + author=bret, title="The Desert Spear", year=2010, ranking=9 + ).save() books = await Book.objects.all() assert books[0] == twok diff --git a/tests/test_ordering/test_default_relation_order.py b/tests/test_ordering/test_default_relation_order.py index 6e49bdea6..27e0a628f 100644 --- a/tests/test_ordering/test_default_relation_order.py +++ b/tests/test_ordering/test_default_relation_order.py @@ -2,11 +2,11 @@ from uuid import UUID, uuid4 import databases +import ormar import pytest import pytest_asyncio import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -30,7 +30,9 @@ class Book(ormar.Model): ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) - author: Optional[Author] = ormar.ForeignKey(Author, orders_by=["name"], related_orders_by=["-year"]) + author: Optional[Author] = ormar.ForeignKey( + Author, orders_by=["name"], related_orders_by=["-year"] + ) title: str = ormar.String(max_length=100) year: int = ormar.Integer(nullable=True) ranking: int = ormar.Integer(nullable=True) @@ -79,8 +81,12 @@ async def test_default_orders_is_applied_from_reverse_relation(): async with database: tolkien = await Author(name="J.R.R. Tolkien").save() hobbit = await Book(author=tolkien, title="The Hobbit", year=1933).save() - silmarillion = await Book(author=tolkien, title="The Silmarillion", year=1977).save() - lotr = await Book(author=tolkien, title="The Lord of the Rings", year=1955).save() + silmarillion = await Book( + author=tolkien, title="The Silmarillion", year=1977 + ).save() + lotr = await Book( + author=tolkien, title="The Lord of the Rings", year=1955 + ).save() tolkien = await Author.objects.select_related("books").get() assert tolkien.books[2] == hobbit @@ -92,9 +98,13 @@ async def test_default_orders_is_applied_from_reverse_relation(): async def test_default_orders_is_applied_from_relation(): async with database: bret = await Author(name="Peter V. Bret").save() - tds = await Book(author=bret, title="The Desert Spear", year=2010, ranking=9).save() + tds = await Book( + author=bret, title="The Desert Spear", year=2010, ranking=9 + ).save() sanders = await Author(name="Brandon Sanderson").save() - twok = await Book(author=sanders, title="The Way of Kings", year=2010, ranking=10).save() + twok = await Book( + author=sanders, title="The Way of Kings", year=2010, ranking=10 + ).save() books = await Book.objects.order_by("year").select_related("author").all() assert books[0] == twok @@ -123,7 +133,6 @@ async def test_default_orders_is_applied_from_relation_on_m2m(): @pytest.mark.asyncio async def test_default_orders_is_applied_from_reverse_relation_on_m2m(): async with database: - max = await Animal(name="Max", specie="Dog").save() joe = await Human(name="Joe").save() zack = await Human(name="Zack").save() diff --git a/tests/test_ordering/test_default_through_relation_order.py b/tests/test_ordering/test_default_through_relation_order.py index e05a7a553..b2a59b07e 100644 --- a/tests/test_ordering/test_default_through_relation_order.py +++ b/tests/test_ordering/test_default_through_relation_order.py @@ -2,12 +2,18 @@ from uuid import UUID, uuid4 import databases +import ormar import pytest import sqlalchemy +from ormar import ( + Model, + ModelDefinitionError, + QuerySet, + pre_relation_remove, + pre_save, + pre_update, +) -import ormar -from ormar import ModelDefinitionError, Model, QuerySet, pre_relation_remove, pre_update -from ormar import pre_save from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -79,7 +85,9 @@ async def test_ordering_by_through_fail(): await alice.load_all() -def _get_filtered_query(sender: Type[Model], instance: Model, to_class: Type[Model]) -> QuerySet: +def _get_filtered_query( + sender: Type[Model], instance: Model, to_class: Type[Model] +) -> QuerySet: """ Helper function. Gets the query filtered by the appropriate class name. @@ -90,7 +98,9 @@ def _get_filtered_query(sender: Type[Model], instance: Model, to_class: Type[Mod return query -def _get_through_model_relations(sender: Type[Model], instance: Model) -> Tuple[Type[Model], Type[Model]]: +def _get_through_model_relations( + sender: Type[Model], instance: Model +) -> Tuple[Type[Model], Type[Model]]: relations = list(instance.extract_related_names()) rel_one = sender.ormar_config.model_fields[relations[0]].to rel_two = sender.ormar_config.model_fields[relations[1]].to @@ -151,7 +161,9 @@ async def _reorder_on_update( setattr(link, order, ind) else: setattr(link, order, ind + 1) - await sender.objects.bulk_update(cast(List[Model], to_reorder), columns=[order]) + await sender.objects.bulk_update( + cast(List[Model], to_reorder), columns=[order] + ) @pre_save(Link) @@ -162,12 +174,18 @@ async def order_link_on_insert(sender: Type[Model], instance: Model, **kwargs: A sender class, instance and have to accept **kwargs even if it's empty as of now. """ rel_one, rel_two = _get_through_model_relations(sender, instance) - await _populate_order_on_insert(sender=sender, instance=instance, from_class=rel_one, to_class=rel_two) - await _populate_order_on_insert(sender=sender, instance=instance, from_class=rel_two, to_class=rel_one) + await _populate_order_on_insert( + sender=sender, instance=instance, from_class=rel_one, to_class=rel_two + ) + await _populate_order_on_insert( + sender=sender, instance=instance, from_class=rel_two, to_class=rel_one + ) @pre_update(Link) -async def reorder_links_on_update(sender: Type[ormar.Model], instance: ormar.Model, passed_args: Dict, **kwargs: Any): +async def reorder_links_on_update( + sender: Type[ormar.Model], instance: ormar.Model, passed_args: Dict, **kwargs: Any +): """ Signal receiver registered on Link model, triggered every time before one is updated by calling update() on a model. Note that signal functions for pre_update signal @@ -237,12 +255,16 @@ async def test_ordering_by_through_on_m2m_field(): async with database: def verify_order(instance, expected): - field_name = "favoriteAnimals" if isinstance(instance, Human) else "favoriteHumans" - order_field_name = "animal_order" if isinstance(instance, Human) else "human_order" + field_name = ( + "favoriteAnimals" if isinstance(instance, Human) else "favoriteHumans" + ) + order_field_name = ( + "animal_order" if isinstance(instance, Human) else "human_order" + ) assert [x.name for x in getattr(instance, field_name)] == expected - assert [getattr(x.link, order_field_name) for x in getattr(instance, field_name)] == [ - i for i in range(len(expected)) - ] + assert [ + getattr(x.link, order_field_name) for x in getattr(instance, field_name) + ] == [i for i in range(len(expected))] alice = await Human(name="Alice").save() bob = await Human(name="Bob").save() @@ -306,6 +328,8 @@ def verify_order(instance, expected): bob = await noodle.favoriteHumans.get(pk=bob.pk) assert bob.link.human_order == 1 - await noodle.favoriteHumans.remove(await noodle.favoriteHumans.filter(link__human_order=2).get()) + await noodle.favoriteHumans.remove( + await noodle.favoriteHumans.filter(link__human_order=2).get() + ) await noodle.load_all() verify_order(noodle, ["Alice", "Bob", "Zack"]) diff --git a/tests/test_ordering/test_proper_order_of_sorting_apply.py b/tests/test_ordering/test_proper_order_of_sorting_apply.py index 6ad597522..96dfb1fc7 100644 --- a/tests/test_ordering/test_proper_order_of_sorting_apply.py +++ b/tests/test_ordering/test_proper_order_of_sorting_apply.py @@ -1,11 +1,11 @@ from typing import Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -17,18 +17,16 @@ database=database, ) -class Author(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "authors") +class Author(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "books", - order_by = ["-ranking"]) - + ormar_config = base_ormar_config.copy(tablename="books", order_by=["-ranking"]) id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey( diff --git a/tests/test_queries/test_adding_related.py b/tests/test_queries/test_adding_related.py index cfba88532..c6ce9e2dc 100644 --- a/tests/test_queries/test_adding_related.py +++ b/tests/test_queries/test_adding_related.py @@ -1,11 +1,9 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy -import asyncio - -import ormar from tests.settings import DATABASE_URL @@ -15,8 +13,8 @@ class Department(ormar.Model): ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -25,8 +23,8 @@ class Department(ormar.Model): class Course(ormar.Model): ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_queries/test_aggr_functions.py b/tests/test_queries/test_aggr_functions.py index 313bf7265..c74b77fbe 100644 --- a/tests/test_queries/test_aggr_functions.py +++ b/tests/test_queries/test_aggr_functions.py @@ -1,12 +1,12 @@ from typing import Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy - -import ormar from ormar.exceptions import QueryDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -18,19 +18,18 @@ database=database, ) -class Author(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "authors", - order_by = ["-name"]) +class Author(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"]) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "books", - order_by = ["year", "-ranking"]) - + ormar_config = base_ormar_config.copy( + tablename="books", order_by=["year", "-ranking"] + ) id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) diff --git a/tests/test_queries/test_deep_relations_select_all.py b/tests/test_queries/test_deep_relations_select_all.py index f53f8a575..7f2caf46f 100644 --- a/tests/test_queries/test_deep_relations_select_all.py +++ b/tests/test_queries/test_deep_relations_select_all.py @@ -1,9 +1,9 @@ import databases +import ormar import pytest +import sqlalchemy from sqlalchemy import func -import ormar -import sqlalchemy from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -12,9 +12,9 @@ class Chart(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "charts", - database = database, - metadata = metadata, + tablename="charts", + database=database, + metadata=metadata, ) chart_id = ormar.Integer(primary_key=True, autoincrement=True) @@ -30,9 +30,9 @@ class Chart(ormar.Model): class Report(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "reports", - database = database, - metadata = metadata, + tablename="reports", + database=database, + metadata=metadata, ) report_id = ormar.Integer(primary_key=True, autoincrement=True) @@ -43,9 +43,9 @@ class Report(ormar.Model): class Language(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "languages", - database = database, - metadata = metadata, + tablename="languages", + database=database, + metadata=metadata, ) language_id = ormar.Integer(primary_key=True, autoincrement=True) @@ -55,9 +55,9 @@ class Language(ormar.Model): class TranslationNode(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "translation_nodes", - database = database, - metadata = metadata, + tablename="translation_nodes", + database=database, + metadata=metadata, ) node_id = ormar.Integer(primary_key=True, autoincrement=True) @@ -66,9 +66,9 @@ class TranslationNode(ormar.Model): class Translation(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "translations", - database = database, - metadata = metadata, + tablename="translations", + database=database, + metadata=metadata, ) translation_id = ormar.Integer(primary_key=True, autoincrement=True) @@ -79,9 +79,9 @@ class Translation(ormar.Model): class Filter(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "filters", - database = database, - metadata = metadata, + tablename="filters", + database=database, + metadata=metadata, ) filter_id = ormar.Integer(primary_key=True, autoincrement=True) @@ -97,9 +97,9 @@ class Filter(ormar.Model): class FilterValue(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "filter_values", - database = database, - metadata = metadata, + tablename="filter_values", + database=database, + metadata=metadata, ) value_id = ormar.Integer(primary_key=True, autoincrement=True) @@ -111,9 +111,9 @@ class FilterValue(ormar.Model): class FilterXReport(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "filters_x_reports", - database = database, - metadata = metadata, + tablename="filters_x_reports", + database=database, + metadata=metadata, ) filter_x_report_id = ormar.Integer(primary_key=True) @@ -126,9 +126,9 @@ class FilterXReport(ormar.Model): class ChartXReport(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "charts_x_reports", - database = database, - metadata = metadata, + tablename="charts_x_reports", + database=database, + metadata=metadata, ) chart_x_report_id = ormar.Integer(primary_key=True) @@ -140,9 +140,9 @@ class ChartXReport(ormar.Model): class ChartColumn(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "charts_columns", - database = database, - metadata = metadata, + tablename="charts_columns", + database=database, + metadata=metadata, ) column_id = ormar.Integer(primary_key=True, autoincrement=True) diff --git a/tests/test_queries/test_filter_groups.py b/tests/test_queries/test_filter_groups.py index d318276ba..1eb002b49 100644 --- a/tests/test_queries/test_filter_groups.py +++ b/tests/test_queries/test_filter_groups.py @@ -1,9 +1,9 @@ from typing import Optional import databases +import ormar import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -15,15 +15,16 @@ database=database, ) + class Author(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "authors") + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "books") + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) diff --git a/tests/test_queries/test_indirect_relations_to_self.py b/tests/test_queries/test_indirect_relations_to_self.py index d28d135be..c9e5094be 100644 --- a/tests/test_queries/test_indirect_relations_to_self.py +++ b/tests/test_queries/test_indirect_relations_to_self.py @@ -1,10 +1,10 @@ from datetime import datetime import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -13,9 +13,9 @@ class Node(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "node", - database = database, - metadata = metadata, + tablename="node", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -26,9 +26,9 @@ class Node(ormar.Model): class Edge(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "edge", - database = database, - metadata = metadata, + tablename="edge", + database=database, + metadata=metadata, ) id: str = ormar.String(primary_key=True, max_length=12) diff --git a/tests/test_queries/test_isnull_filter.py b/tests/test_queries/test_isnull_filter.py index 31cc8b0bc..e3e421459 100644 --- a/tests/test_queries/test_isnull_filter.py +++ b/tests/test_queries/test_isnull_filter.py @@ -1,10 +1,10 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -16,17 +16,16 @@ database=database, ) -class Author(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "authors") +class Author(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "books") - + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -36,9 +35,9 @@ class Book(ormar.Model): class JsonModel(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, - tablename = "jsons", + metadata=metadata, + database=database, + tablename="jsons", ) id = ormar.Integer(primary_key=True) diff --git a/tests/test_queries/test_nested_reverse_relations.py b/tests/test_queries/test_nested_reverse_relations.py index 6938f2553..679b53b7c 100644 --- a/tests/test_queries/test_nested_reverse_relations.py +++ b/tests/test_queries/test_nested_reverse_relations.py @@ -1,10 +1,10 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -16,17 +16,16 @@ database=database, ) -class DataSource(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "datasources") +class DataSource(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="datasources") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, unique=True, index=True) class DataSourceTable(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "source_tables") - + ormar_config = base_ormar_config.copy(tablename="source_tables") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, index=True) @@ -36,7 +35,7 @@ class DataSourceTable(ormar.Model): class DataSourceTableColumn(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "source_columns") + ormar_config = base_ormar_config.copy(tablename="source_columns") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, index=True) diff --git a/tests/test_queries/test_non_relation_fields_not_merged.py b/tests/test_queries/test_non_relation_fields_not_merged.py index c4732a1ce..b64302bd2 100644 --- a/tests/test_queries/test_non_relation_fields_not_merged.py +++ b/tests/test_queries/test_non_relation_fields_not_merged.py @@ -1,10 +1,10 @@ -from typing import Dict, List, Optional +from typing import Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -16,15 +16,16 @@ database=database, ) + class Chart(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "authors") + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) datasets = ormar.JSON() class Config(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "books") + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) chart: Optional[Chart] = ormar.ForeignKey(Chart) diff --git a/tests/test_queries/test_or_filters.py b/tests/test_queries/test_or_filters.py index b839d6289..039d3df84 100644 --- a/tests/test_queries/test_or_filters.py +++ b/tests/test_queries/test_or_filters.py @@ -1,11 +1,11 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar.exceptions import QueryDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -123,7 +123,10 @@ async def test_or_filters(): ( ( (Book.year > 1960) & (Book.author.name == "J.R.R. Tolkien") - | ((Book.year < 2000) & (Book.author.name == "Andrzej Sapkowski")) + | ( + (Book.year < 2000) + & (Book.author.name == "Andrzej Sapkowski") + ) ) & (Book.title.startswith("The")) ) @@ -179,7 +182,9 @@ async def test_or_filters(): .all() ) assert len(books) == 3 - assert not any([x.title in ["The Tower of Fools", "The Lord of the Rings"] for x in books]) + assert not any( + [x.title in ["The Tower of Fools", "The Lord of the Rings"] for x in books] + ) books = ( await Book.objects.select_related("author") @@ -227,16 +232,24 @@ async def test_or_filters(): with pytest.raises(QueryDefinitionError): await Book.objects.select_related("author").filter("wrong").all() - books = await tolkien.books.filter(ormar.or_(year__lt=1940, year__gt=1960)).all() + books = await tolkien.books.filter( + ormar.or_(year__lt=1940, year__gt=1960) + ).all() assert len(books) == 2 books = await tolkien.books.filter( - ormar.and_(ormar.or_(year__lt=1940, year__gt=1960), title__icontains="hobbit") + ormar.and_( + ormar.or_(year__lt=1940, year__gt=1960), title__icontains="hobbit" + ) ).all() assert len(books) == 1 assert tolkien.books[0].title == "The Hobbit" - books = await Book.objects.select_related("author").filter(ormar.or_(author__name="J.R.R. Tolkien")).all() + books = ( + await Book.objects.select_related("author") + .filter(ormar.or_(author__name="J.R.R. Tolkien")) + .all() + ) assert len(books) == 3 books = ( diff --git a/tests/test_queries/test_order_by.py b/tests/test_queries/test_order_by.py index e4f90bec5..187381aa4 100644 --- a/tests/test_queries/test_order_by.py +++ b/tests/test_queries/test_order_by.py @@ -1,10 +1,10 @@ from typing import List, Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -13,9 +13,9 @@ class Song(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "songs", - metadata = metadata, - database = database, + tablename="songs", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -25,9 +25,9 @@ class Song(ormar.Model): class Owner(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "owners", - metadata = metadata, - database = database, + tablename="owners", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -36,9 +36,9 @@ class Owner(ormar.Model): class AliasNested(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "aliases_nested", - metadata = metadata, - database = database, + tablename="aliases_nested", + metadata=metadata, + database=database, ) id: int = ormar.Integer(name="alias_id", primary_key=True) @@ -47,9 +47,9 @@ class AliasNested(ormar.Model): class AliasTest(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "aliases", - metadata = metadata, - database = database, + tablename="aliases", + metadata=metadata, + database=database, ) id: int = ormar.Integer(name="alias_id", primary_key=True) @@ -59,9 +59,9 @@ class AliasTest(ormar.Model): class Toy(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "toys", - metadata = metadata, - database = database, + tablename="toys", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -71,9 +71,9 @@ class Toy(ormar.Model): class Factory(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "factories", - metadata = metadata, - database = database, + tablename="factories", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -82,9 +82,9 @@ class Factory(ormar.Model): class Car(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "cars", - metadata = metadata, - database = database, + tablename="cars", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -94,9 +94,9 @@ class Car(ormar.Model): class User(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "users", - metadata = metadata, - database = database, + tablename="users", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_queries/test_pagination.py b/tests/test_queries/test_pagination.py index 7a1dfec21..b36360c1f 100644 --- a/tests/test_queries/test_pagination.py +++ b/tests/test_queries/test_pagination.py @@ -1,9 +1,9 @@ import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar.exceptions import QueryDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) diff --git a/tests/test_queries/test_queryproxy_on_m2m_models.py b/tests/test_queries/test_queryproxy_on_m2m_models.py index 430dae7f9..4108a52a7 100644 --- a/tests/test_queries/test_queryproxy_on_m2m_models.py +++ b/tests/test_queries/test_queryproxy_on_m2m_models.py @@ -1,12 +1,11 @@ -import asyncio from typing import List, Optional, Union import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar.exceptions import QueryDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -15,9 +14,9 @@ class Subject(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "subjects", - database = database, - metadata = metadata, + tablename="subjects", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -26,9 +25,9 @@ class Subject(ormar.Model): class Author(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "authors", - database = database, - metadata = metadata, + tablename="authors", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -38,9 +37,9 @@ class Author(ormar.Model): class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - database = database, - metadata = metadata, + tablename="categories", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -51,17 +50,17 @@ class Category(ormar.Model): class PostCategory(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "posts_categories", - database = database, - metadata = metadata, + tablename="posts_categories", + database=database, + metadata=metadata, ) class Post(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "posts", - database = database, - metadata = metadata, + tablename="posts", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_queries/test_queryset_level_methods.py b/tests/test_queries/test_queryset_level_methods.py index 76bfe6bfa..b4509c3e5 100644 --- a/tests/test_queries/test_queryset_level_methods.py +++ b/tests/test_queries/test_queryset_level_methods.py @@ -2,18 +2,18 @@ from typing import Optional import databases +import ormar import pydantic import pytest import sqlalchemy -from pydantic import Json - -import ormar from ormar import QuerySet from ormar.exceptions import ( + ModelListEmptyError, ModelPersistenceError, QueryDefinitionError, - ModelListEmptyError, ) +from pydantic import Json + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -27,9 +27,9 @@ class MySize(Enum): class Book(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "books", - metadata = metadata, - database = database, + tablename="books", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -44,9 +44,9 @@ class Book(ormar.Model): class ToDo(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "todos", - metadata = metadata, - database = database, + tablename="todos", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -58,9 +58,9 @@ class ToDo(ormar.Model): class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - metadata = metadata, - database = database, + tablename="categories", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -69,9 +69,9 @@ class Category(ormar.Model): class Note(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "notes", - metadata = metadata, - database = database, + tablename="notes", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -81,9 +81,9 @@ class Note(ormar.Model): class ItemConfig(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, - tablename = "item_config", + metadata=metadata, + database=database, + tablename="item_config", ) id: Optional[int] = ormar.Integer(primary_key=True) @@ -103,10 +103,10 @@ async def first_or_404(self, *args, **kwargs): class Customer(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, - tablename = "customer", - queryset_class = QuerySetCls, + metadata=metadata, + database=database, + tablename="customer", + queryset_class=QuerySetCls, ) id: Optional[int] = ormar.Integer(primary_key=True) @@ -115,9 +115,9 @@ class Customer(ormar.Model): class JsonTestModel(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, - tablename = "test_model", + metadata=metadata, + database=database, + tablename="test_model", ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_queries/test_quoting_table_names_in_on_join_clause.py b/tests/test_queries/test_quoting_table_names_in_on_join_clause.py index c78cc21bc..921cbbb90 100644 --- a/tests/test_queries/test_quoting_table_names_in_on_join_clause.py +++ b/tests/test_queries/test_quoting_table_names_in_on_join_clause.py @@ -3,11 +3,11 @@ from typing import Dict, Optional, Union import databases +import ormar import pytest import sqlalchemy from sqlalchemy import create_engine -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -17,9 +17,9 @@ class Team(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "team", - database = database, - metadata = metadata, + tablename="team", + database=database, + metadata=metadata, ) id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) @@ -31,9 +31,9 @@ class Team(ormar.Model): class User(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "user", - database = database, - metadata = metadata, + tablename="user", + database=database, + metadata=metadata, ) id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) @@ -44,9 +44,9 @@ class User(ormar.Model): class Order(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "order", - database = database, - metadata = metadata, + tablename="order", + database=database, + metadata=metadata, ) id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) diff --git a/tests/test_queries/test_reserved_sql_keywords_escaped.py b/tests/test_queries/test_reserved_sql_keywords_escaped.py index 68c82741e..544d714d3 100644 --- a/tests/test_queries/test_reserved_sql_keywords_escaped.py +++ b/tests/test_queries/test_reserved_sql_keywords_escaped.py @@ -1,9 +1,8 @@ import databases +import ormar import pytest import sqlalchemy -import ormar - from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -15,8 +14,9 @@ database=database, ) + class User(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "user") + ormar_config = base_ormar_config.copy(tablename="user") id: int = ormar.Integer(primary_key=True, autoincrement=True, nullable=False) user: str = ormar.String( @@ -32,7 +32,7 @@ class User(ormar.Model): class Task(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "task") + ormar_config = base_ormar_config.copy(tablename="task") id: int = ormar.Integer(primary_key=True, autoincrement=True, nullable=False) from_: str = ormar.String(name="from", nullable=True, max_length=200) diff --git a/tests/test_queries/test_reverse_fk_queryset.py b/tests/test_queries/test_reverse_fk_queryset.py index 5ed881074..425653ed6 100644 --- a/tests/test_queries/test_reverse_fk_queryset.py +++ b/tests/test_queries/test_reverse_fk_queryset.py @@ -1,11 +1,11 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar import NoMatch + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -14,9 +14,9 @@ class Album(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "albums", - metadata = metadata, - database = database, + tablename="albums", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True, name="album_id") @@ -26,9 +26,9 @@ class Album(ormar.Model): class Writer(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "writers", - metadata = metadata, - database = database, + tablename="writers", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True, name="writer_id") @@ -37,9 +37,9 @@ class Writer(ormar.Model): class Track(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "tracks", - metadata = metadata, - database = database, + tablename="tracks", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_queries/test_selecting_subset_of_columns.py b/tests/test_queries/test_selecting_subset_of_columns.py index 14f5f15e1..e839103aa 100644 --- a/tests/test_queries/test_selecting_subset_of_columns.py +++ b/tests/test_queries/test_selecting_subset_of_columns.py @@ -1,14 +1,14 @@ import asyncio import itertools -from typing import Optional, List +from typing import List, Optional import databases +import ormar import pydantic import pytest import pytest_asyncio import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -17,9 +17,9 @@ class NickNames(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "nicks", - metadata = metadata, - database = database, + tablename="nicks", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -29,17 +29,17 @@ class NickNames(ormar.Model): class NicksHq(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "nicks_x_hq", - metadata = metadata, - database = database, + tablename="nicks_x_hq", + metadata=metadata, + database=database, ) class HQ(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "hqs", - metadata = metadata, - database = database, + tablename="hqs", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -49,9 +49,9 @@ class HQ(ormar.Model): class Company(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "companies", - metadata = metadata, - database = database, + tablename="companies", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -62,9 +62,9 @@ class Company(ormar.Model): class Car(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "cars", - metadata = metadata, - database = database, + tablename="cars", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_queries/test_values_and_values_list.py b/tests/test_queries/test_values_and_values_list.py index 222d9cc2c..323ef55fa 100644 --- a/tests/test_queries/test_values_and_values_list.py +++ b/tests/test_queries/test_values_and_values_list.py @@ -2,12 +2,12 @@ from typing import List, Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy - -import ormar from ormar.exceptions import QueryDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -36,7 +36,7 @@ class Role(ormar.Model): class Category(ormar.Model): - ormar_config = base_ormar_config.copy( tablename = "categories") + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) diff --git a/tests/test_relations/test_cascades.py b/tests/test_relations/test_cascades.py index d2c5fdc02..931f7625c 100644 --- a/tests/test_relations/test_cascades.py +++ b/tests/test_relations/test_cascades.py @@ -1,11 +1,11 @@ from typing import Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) diff --git a/tests/test_relations/test_customizing_through_model_relation_names.py b/tests/test_relations/test_customizing_through_model_relation_names.py index 62ec66c4f..76c0088c0 100644 --- a/tests/test_relations/test_customizing_through_model_relation_names.py +++ b/tests/test_relations/test_customizing_through_model_relation_names.py @@ -1,8 +1,8 @@ import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL metadata = sqlalchemy.MetaData() @@ -72,9 +72,15 @@ async def test_working_with_changed_through_names(): student = await course_check.students.get(name="Jack") assert student.name == "Jack" - students = await Student.objects.select_related("courses").all(courses__course_name="basic1") + students = await Student.objects.select_related("courses").all( + courses__course_name="basic1" + ) assert len(students) == 2 - course_check = await Course.objects.select_related("students").order_by("students__name").get() + course_check = ( + await Course.objects.select_related("students") + .order_by("students__name") + .get() + ) assert course_check.students[0].name == "Abi" assert course_check.students[1].name == "Jack" diff --git a/tests/test_relations/test_database_fk_creation.py b/tests/test_relations/test_database_fk_creation.py index 331e66a4c..58efffbbc 100644 --- a/tests/test_relations/test_database_fk_creation.py +++ b/tests/test_relations/test_database_fk_creation.py @@ -1,11 +1,11 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar.fields.foreign_key import validate_referential_action + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -93,7 +93,7 @@ def test_simple_cascade(): def test_validations_referential_action(): CASCADE = ormar.ReferentialAction.CASCADE.value - assert validate_referential_action(None) == None + assert validate_referential_action(None) is None assert validate_referential_action("cascade") == CASCADE assert validate_referential_action(ormar.ReferentialAction.CASCADE) == CASCADE @@ -107,7 +107,7 @@ async def test_cascade_clear(): async with database.transaction(force_rollback=True): a = await A.objects.create(name="a") b = await B.objects.create(name="b", a=a) - c = await C.objects.create(name="c", b=b) + await C.objects.create(name="c", b=b) await a.bs.clear(keep_reversed=False) diff --git a/tests/test_relations/test_foreign_keys.py b/tests/test_relations/test_foreign_keys.py index 7caa5aaf1..1899aa00f 100644 --- a/tests/test_relations/test_foreign_keys.py +++ b/tests/test_relations/test_foreign_keys.py @@ -1,11 +1,11 @@ from typing import Optional import databases +import ormar import pytest import sqlalchemy +from ormar.exceptions import MultipleMatches, NoMatch, RelationshipInstanceError -import ormar -from ormar.exceptions import NoMatch, MultipleMatches, RelationshipInstanceError from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -14,9 +14,9 @@ class Album(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "albums", - metadata = metadata, - database = database, + tablename="albums", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -26,9 +26,9 @@ class Album(ormar.Model): class Track(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "tracks", - metadata = metadata, - database = database, + tablename="tracks", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -41,9 +41,9 @@ class Track(ormar.Model): class Cover(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "covers", - metadata = metadata, - database = database, + tablename="covers", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -53,9 +53,9 @@ class Cover(ormar.Model): class Organisation(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "org", - metadata = metadata, - database = database, + tablename="org", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -64,9 +64,9 @@ class Organisation(ormar.Model): class Team(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "teams", - metadata = metadata, - database = database, + tablename="teams", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -76,9 +76,9 @@ class Team(ormar.Model): class Member(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "members", - metadata = metadata, - database = database, + tablename="members", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_relations/test_m2m_through_fields.py b/tests/test_relations/test_m2m_through_fields.py index 61390c720..4f1eb849c 100644 --- a/tests/test_relations/test_m2m_through_fields.py +++ b/tests/test_relations/test_m2m_through_fields.py @@ -1,11 +1,10 @@ -from typing import Any, Sequence, cast +from typing import Any, ForwardRef import databases +import ormar import pytest import sqlalchemy -from typing import ForwardRef -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -19,16 +18,14 @@ class Category(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "categories") - + ormar_config = base_ormar_config.copy(tablename="categories") id = ormar.Integer(primary_key=True) name = ormar.String(max_length=40) class PostCategory(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "posts_x_categories") - + ormar_config = base_ormar_config.copy(tablename="posts_x_categories") id: int = ormar.Integer(primary_key=True) sort_order: int = ormar.Integer(nullable=True) @@ -61,8 +58,7 @@ def create_test_database(): class PostCategory2(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "posts_x_categories2") - + ormar_config = base_ormar_config.copy(tablename="posts_x_categories2") id: int = ormar.Integer(primary_key=True) sort_order: int = ormar.Integer(nullable=True) diff --git a/tests/test_relations/test_many_to_many.py b/tests/test_relations/test_many_to_many.py index 251023c0e..044724a16 100644 --- a/tests/test_relations/test_many_to_many.py +++ b/tests/test_relations/test_many_to_many.py @@ -2,12 +2,12 @@ from typing import List, Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy - -import ormar from ormar.exceptions import ModelPersistenceError, NoMatch, RelationshipInstanceError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -151,7 +151,9 @@ async def test_quering_of_the_m2m_models(cleanup): category = await Category.objects.filter(posts__author=guido).get() assert category == news # or: - category2 = await Category.objects.filter(posts__author__first_name="Guido").get() + category2 = await Category.objects.filter( + posts__author__first_name="Guido" + ).get() assert category2 == news diff --git a/tests/test_relations/test_postgress_select_related_with_limit.py b/tests/test_relations/test_postgress_select_related_with_limit.py index 05dd41f34..e432255b7 100644 --- a/tests/test_relations/test_postgress_select_related_with_limit.py +++ b/tests/test_relations/test_postgress_select_related_with_limit.py @@ -4,14 +4,11 @@ from enum import Enum from typing import Optional -from pydantic import EmailStr - import databases -import sqlalchemy -from sqlalchemy import create_engine - import ormar import pytest +import sqlalchemy +from sqlalchemy import create_engine from tests.settings import DATABASE_URL @@ -29,8 +26,8 @@ class Level(Enum): base_ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, + database=database, + metadata=metadata, ) @@ -47,9 +44,8 @@ class User(PrimaryKeyMixin, ormar.Model): fullname: Optional[str] = ormar.String(max_length=64, nullable=True, default=None) is_active: bool = ormar.Boolean(index=True, nullable=False, default=True) - ormar_config = base_ormar_config.copy( - order_by = ["-is_active", "-level"] - ) + ormar_config = base_ormar_config.copy(order_by=["-is_active", "-level"]) + class Task(PrimaryKeyMixin, ormar.Model): """Task Model Class to Implement Method for Operations of Task Entity""" @@ -62,11 +58,11 @@ class Task(PrimaryKeyMixin, ormar.Model): user: User = ormar.ForeignKey(to=User) ormar_config = base_ormar_config.copy( - order_by = ["-end_date", "-start_date"], - constraints = [ + order_by=["-end_date", "-start_date"], + constraints=[ ormar.UniqueColumns("user", "name"), - ] - ) + ], + ) @pytest.fixture(autouse=True, scope="module") diff --git a/tests/test_relations/test_prefetch_related.py b/tests/test_relations/test_prefetch_related.py index 1b9859500..ab054d50e 100644 --- a/tests/test_relations/test_prefetch_related.py +++ b/tests/test_relations/test_prefetch_related.py @@ -1,10 +1,10 @@ from typing import List, Optional import databases +import ormar import pytest import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -13,9 +13,9 @@ class RandomSet(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "randoms", - metadata = metadata, - database = database, + tablename="randoms", + metadata=metadata, + database=database, ) id: int = ormar.Integer(name="random_id", primary_key=True) @@ -24,9 +24,9 @@ class RandomSet(ormar.Model): class Tonation(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "tonations", - metadata = metadata, - database = database, + tablename="tonations", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -36,9 +36,9 @@ class Tonation(ormar.Model): class Division(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "divisions", - metadata = metadata, - database = database, + tablename="divisions", + metadata=metadata, + database=database, ) id: int = ormar.Integer(name="division_id", primary_key=True) @@ -47,9 +47,9 @@ class Division(ormar.Model): class Shop(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "shops", - metadata = metadata, - database = database, + tablename="shops", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -59,17 +59,17 @@ class Shop(ormar.Model): class AlbumShops(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "albums_x_shops", - metadata = metadata, - database = database, + tablename="albums_x_shops", + metadata=metadata, + database=database, ) class Album(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "albums", - metadata = metadata, - database = database, + tablename="albums", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -79,9 +79,9 @@ class Album(ormar.Model): class Track(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "tracks", - metadata = metadata, - database = database, + tablename="tracks", + metadata=metadata, + database=database, ) id: int = ormar.Integer(name="track_id", primary_key=True) @@ -93,9 +93,9 @@ class Track(ormar.Model): class Cover(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "covers", - metadata = metadata, - database = database, + tablename="covers", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_relations/test_prefetch_related_multiple_models_relation.py b/tests/test_relations/test_prefetch_related_multiple_models_relation.py index 2750b00e6..bd077a3fb 100644 --- a/tests/test_relations/test_prefetch_related_multiple_models_relation.py +++ b/tests/test_relations/test_prefetch_related_multiple_models_relation.py @@ -1,11 +1,10 @@ from typing import List, Optional import databases -import sqlalchemy -from sqlalchemy import create_engine - import ormar import pytest +import sqlalchemy +from sqlalchemy import create_engine from tests.settings import DATABASE_URL @@ -15,9 +14,9 @@ class User(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, - tablename = "test_users", + metadata=metadata, + database=db, + tablename="test_users", ) id: int = ormar.Integer(primary_key=True) @@ -26,9 +25,9 @@ class User(ormar.Model): class Signup(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, - tablename = "test_signup", + metadata=metadata, + database=db, + tablename="test_signup", ) id: int = ormar.Integer(primary_key=True) @@ -36,9 +35,9 @@ class Signup(ormar.Model): class Session(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, - tablename = "test_sessions", + metadata=metadata, + database=db, + tablename="test_sessions", ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_relations/test_python_style_relations.py b/tests/test_relations/test_python_style_relations.py index fb5786a85..422b9ec26 100644 --- a/tests/test_relations/test_python_style_relations.py +++ b/tests/test_relations/test_python_style_relations.py @@ -1,11 +1,11 @@ from typing import List, Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -14,9 +14,9 @@ class Author(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "authors", - database = database, - metadata = metadata, + tablename="authors", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -26,9 +26,9 @@ class Author(ormar.Model): class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - database = database, - metadata = metadata, + tablename="categories", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -37,9 +37,9 @@ class Category(ormar.Model): class Post(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "posts", - database = database, - metadata = metadata, + tablename="posts", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_relations/test_relations_default_exception.py b/tests/test_relations/test_relations_default_exception.py index 5b1104cf6..d88d899b4 100644 --- a/tests/test_relations/test_relations_default_exception.py +++ b/tests/test_relations/test_relations_default_exception.py @@ -2,11 +2,11 @@ from typing import List, Optional import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar.exceptions import ModelDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -15,9 +15,9 @@ class Author(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "authors", - database = database, - metadata = metadata, + tablename="authors", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -27,9 +27,9 @@ class Author(ormar.Model): class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - database = database, - metadata = metadata, + tablename="categories", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -41,9 +41,9 @@ def test_fk_error(): class Post(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "posts", - database = database, - metadata = metadata, + tablename="posts", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) @@ -57,9 +57,9 @@ def test_m2m_error(): class Post(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "posts", - database = database, - metadata = metadata, + tablename="posts", + database=database, + metadata=metadata, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_relations/test_saving_related.py b/tests/test_relations/test_saving_related.py index 8b6c23c60..31e9d5d52 100644 --- a/tests/test_relations/test_saving_related.py +++ b/tests/test_relations/test_saving_related.py @@ -1,12 +1,12 @@ from typing import Union import databases +import ormar import pytest import sqlalchemy as sa +from ormar.exceptions import ModelPersistenceError from sqlalchemy import create_engine -import ormar -from ormar.exceptions import ModelPersistenceError from tests.settings import DATABASE_URL metadata = sa.MetaData() @@ -15,9 +15,9 @@ class Category(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "categories", - metadata = metadata, - database = db, + tablename="categories", + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) @@ -27,9 +27,9 @@ class Category(ormar.Model): class Workshop(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "workshops", - metadata = metadata, - database = db, + tablename="workshops", + metadata=metadata, + database=db, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_relations/test_select_related_with_limit.py b/tests/test_relations/test_select_related_with_limit.py index 221749148..36d3785ce 100644 --- a/tests/test_relations/test_select_related_with_limit.py +++ b/tests/test_relations/test_select_related_with_limit.py @@ -1,11 +1,10 @@ from typing import List, Optional import databases -import sqlalchemy -from sqlalchemy import create_engine - import ormar import pytest +import sqlalchemy +from sqlalchemy import create_engine from tests.settings import DATABASE_URL @@ -15,9 +14,9 @@ class Keyword(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, - tablename = "keywords", + metadata=metadata, + database=db, + tablename="keywords", ) id: int = ormar.Integer(primary_key=True) @@ -26,9 +25,9 @@ class Keyword(ormar.Model): class KeywordPrimaryModel(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, - tablename = "primary_models_keywords", + metadata=metadata, + database=db, + tablename="primary_models_keywords", ) id: int = ormar.Integer(primary_key=True) @@ -36,9 +35,9 @@ class KeywordPrimaryModel(ormar.Model): class PrimaryModel(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, - tablename = "primary_models", + metadata=metadata, + database=db, + tablename="primary_models", ) id: int = ormar.Integer(primary_key=True) @@ -52,9 +51,9 @@ class PrimaryModel(ormar.Model): class SecondaryModel(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = db, - tablename = "secondary_models", + metadata=metadata, + database=db, + tablename="secondary_models", ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py b/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py index 4cf1051fc..a79d79485 100644 --- a/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py +++ b/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py @@ -3,12 +3,12 @@ from typing import List, Optional, Union import databases +import ormar import pytest import sqlalchemy +from ormar import ModelDefinitionError from sqlalchemy import create_engine -import ormar -from ormar import ModelDefinitionError from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -16,8 +16,8 @@ base_ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, + metadata=metadata, + database=database, ) diff --git a/tests/test_relations/test_selecting_proper_table_prefix.py b/tests/test_relations/test_selecting_proper_table_prefix.py index 056abffe4..da5393241 100644 --- a/tests/test_relations/test_selecting_proper_table_prefix.py +++ b/tests/test_relations/test_selecting_proper_table_prefix.py @@ -1,11 +1,11 @@ from typing import List, Optional import databases +import ormar import pytest import sqlalchemy from sqlalchemy import create_engine -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -14,9 +14,9 @@ class User(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, - tablename = "test_users", + metadata=metadata, + database=database, + tablename="test_users", ) id: int = ormar.Integer(primary_key=True) @@ -25,9 +25,9 @@ class User(ormar.Model): class Signup(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, - tablename = "test_signup", + metadata=metadata, + database=database, + tablename="test_signup", ) id: int = ormar.Integer(primary_key=True) @@ -35,9 +35,9 @@ class Signup(ormar.Model): class Session(ormar.Model): ormar_config = ormar.OrmarConfig( - metadata = metadata, - database = database, - tablename = "test_sessions", + metadata=metadata, + database=database, + tablename="test_sessions", ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_relations/test_skipping_reverse.py b/tests/test_relations/test_skipping_reverse.py index 033a3a833..b683b2c6c 100644 --- a/tests/test_relations/test_skipping_reverse.py +++ b/tests/test_relations/test_skipping_reverse.py @@ -1,11 +1,11 @@ from typing import List, Optional import databases +import ormar import pytest import pytest_asyncio import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -27,7 +27,7 @@ class Author(ormar.Model): class Category(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "categories") + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) diff --git a/tests/test_relations/test_through_relations_fail.py b/tests/test_relations/test_through_relations_fail.py index 454462b98..129fc21b2 100644 --- a/tests/test_relations/test_through_relations_fail.py +++ b/tests/test_relations/test_through_relations_fail.py @@ -1,11 +1,11 @@ # type: ignore import databases +import ormar import pytest import sqlalchemy - -import ormar from ormar import ModelDefinitionError + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -14,12 +14,12 @@ def test_through_with_relation_fails(): base_ormar_config = ormar.OrmarConfig( - database = database, - metadata = metadata, + database=database, + metadata=metadata, ) class Category(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "categories") + ormar_config = base_ormar_config.copy(tablename="categories") id = ormar.Integer(primary_key=True) name = ormar.String(max_length=40) @@ -31,8 +31,7 @@ class Blog(ormar.Model): title: str = ormar.String(max_length=200) class PostCategory(ormar.Model): - ormar_config = base_ormar_config.copy(tablename = "posts_x_categories") - + ormar_config = base_ormar_config.copy(tablename="posts_x_categories") id: int = ormar.Integer(primary_key=True) sort_order: int = ormar.Integer(nullable=True) diff --git a/tests/test_relations/test_weakref_checking.py b/tests/test_relations/test_weakref_checking.py index 512a42f41..bdd5afc66 100644 --- a/tests/test_relations/test_weakref_checking.py +++ b/tests/test_relations/test_weakref_checking.py @@ -1,11 +1,7 @@ -from typing import Optional, Type - import databases -import pytest -import pytest_asyncio +import ormar import sqlalchemy -import ormar from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -14,9 +10,9 @@ class Band(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "bands", - metadata = metadata, - database = database, + tablename="bands", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -25,9 +21,9 @@ class Band(ormar.Model): class Artist(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "artists", - metadata = metadata, - database = database, + tablename="artists", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -39,7 +35,7 @@ class Artist(ormar.Model): def test_weakref_init(): band = Band(name="Band") artist1 = Artist(name="Artist 1", band=band) - artist2 = Artist(name="Artist 2", band=band) + Artist(name="Artist 2", band=band) artist3 = Artist(name="Artist 3", band=band) del artist1 diff --git a/tests/test_signals/test_signals.py b/tests/test_signals/test_signals.py index 5622c5ae8..1f574b6fc 100644 --- a/tests/test_signals/test_signals.py +++ b/tests/test_signals/test_signals.py @@ -1,12 +1,11 @@ from typing import Optional import databases +import ormar import pydantic import pytest import pytest_asyncio import sqlalchemy - -import ormar from ormar import ( post_bulk_update, post_delete, @@ -16,8 +15,9 @@ pre_save, pre_update, ) -from ormar.signals import SignalEmitter from ormar.exceptions import SignalDefinitionError +from ormar.signals import SignalEmitter + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -26,9 +26,9 @@ class AuditLog(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "audits", - metadata = metadata, - database = database, + tablename="audits", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -38,9 +38,9 @@ class AuditLog(ormar.Model): class Cover(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "covers", - metadata = metadata, - database = database, + tablename="covers", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -49,9 +49,9 @@ class Cover(ormar.Model): class Album(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "albums", - metadata = metadata, - database = database, + tablename="albums", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_signals/test_signals_for_relations.py b/tests/test_signals/test_signals_for_relations.py index 1fd67d812..08ddcc130 100644 --- a/tests/test_signals/test_signals_for_relations.py +++ b/tests/test_signals/test_signals_for_relations.py @@ -1,18 +1,18 @@ from typing import Optional import databases +import ormar +import pydantic import pytest import pytest_asyncio import sqlalchemy - -import ormar from ormar import ( post_relation_add, post_relation_remove, pre_relation_add, pre_relation_remove, ) -import pydantic + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL, force_rollback=True) @@ -21,9 +21,9 @@ class AuditLog(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "audits", - metadata = metadata, - database = database, + tablename="audits", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -33,9 +33,9 @@ class AuditLog(ormar.Model): class Cover(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "covers", - metadata = metadata, - database = database, + tablename="covers", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) @@ -44,9 +44,9 @@ class Cover(ormar.Model): class Artist(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "artists", - metadata = metadata, - database = database, + tablename="artists", + metadata=metadata, + database=database, ) id: int = ormar.Integer(name="artist_id", primary_key=True) @@ -55,9 +55,9 @@ class Artist(ormar.Model): class Album(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "albums", - metadata = metadata, - database = database, + tablename="albums", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) diff --git a/tests/test_types.py b/tests/test_types.py index 3997a1678..f9bc3c68f 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,13 +1,9 @@ -from typing import Any, Optional, TYPE_CHECKING, TypedDict - import databases +import ormar import pytest import sqlalchemy - -import ormar -from ormar.models.metaclass import ModelMeta from ormar.models.ormar_config import OrmarConfig -from ormar.relations.querysetproxy import QuerysetProxy + from tests.settings import DATABASE_URL database = databases.Database(DATABASE_URL) @@ -15,7 +11,6 @@ class Publisher(ormar.Model): - ormar_config = OrmarConfig( metadata=metadata, database=database, @@ -27,7 +22,6 @@ class Publisher(ormar.Model): class Author(ormar.Model): - ormar_config = OrmarConfig( metadata=metadata, database=database, tablename="authors", order_by=["-name"] ) @@ -38,7 +32,6 @@ class Author(ormar.Model): class Book(ormar.Model): - ormar_config = OrmarConfig( metadata=metadata, database=database, @@ -69,12 +62,10 @@ def assert_type(book: Book): @pytest.mark.asyncio async def test_types() -> None: async with database: - query = Book.objects publisher = await Publisher(name="Test publisher").save() author = await Author.objects.create(name="Test Author") await author.publishers.add(publisher) - author2 = await Author.objects.select_related("publishers").get() - publishers = author2.publishers + await Author.objects.select_related("publishers").get() publisher2 = await Publisher.objects.select_related("authors").get() authors = publisher2.authors assert authors[0] == author @@ -84,8 +75,8 @@ async def test_types() -> None: # reveal_type(author) # iter of relation proxy book = await Book.objects.create(title="Test", author=author) book2 = await Book.objects.select_related("author").get() - books = await Book.objects.select_related("author").all() - author_books = await author.books.all() + await Book.objects.select_related("author").all() + await author.books.all() assert book.author.name == "Test Author" assert book2.author.name == "Test Author" # if TYPE_CHECKING: # pragma: no cover diff --git a/tests/test_utils/test_queryset_utils.py b/tests/test_utils/test_queryset_utils.py index bd52b00a4..c57129e30 100644 --- a/tests/test_utils/test_queryset_utils.py +++ b/tests/test_utils/test_queryset_utils.py @@ -1,14 +1,14 @@ import databases -import sqlalchemy - import ormar +import sqlalchemy from ormar.queryset.queries.prefetch_query import sort_models from ormar.queryset.utils import ( subtract_dict, translate_list_to_dict, - update_dict_from_list, update, + update_dict_from_list, ) + from tests.settings import DATABASE_URL @@ -179,9 +179,9 @@ def test_subtracting_with_set_and_dict(): class SortModel(ormar.Model): ormar_config = ormar.OrmarConfig( - tablename = "sorts", - metadata = metadata, - database = database, + tablename="sorts", + metadata=metadata, + database=database, ) id: int = ormar.Integer(primary_key=True) From e4c977890b26608568f45b9061e8ebfecb53a83d Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 25 Jan 2024 15:24:07 +0100 Subject: [PATCH 26/95] rename jobs --- .github/workflows/test-package.yml | 3 +-- .github/workflows/type-check.yml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 08d361380..25a21cc65 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a single version of Python # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: build +name: test on: push: @@ -65,7 +65,6 @@ jobs: env: DATABASE_URL: "sqlite:///testsuite" run: bash scripts/test.sh - - run: mypy ormar tests benchmarks - name: Upload coverage uses: codecov/codecov-action@v3.1.4 - name: Test & publish code coverage diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml index 13ef05170..025613162 100644 --- a/.github/workflows/type-check.yml +++ b/.github/workflows/type-check.yml @@ -27,5 +27,5 @@ jobs: poetry install --extras "all" env: POETRY_VIRTUALENVS_CREATE: false - - name: Lint + - name: Type check run: python -m mypy . --ignore-missing-imports --install-types --non-interactive From b2a2ab61cd7995d297fcad2a69f3df623203350a Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 25 Jan 2024 15:39:41 +0100 Subject: [PATCH 27/95] fix imports --- ormar/__init__.py | 4 ++-- ormar/fields/__init__.py | 2 +- ormar/models/ormar_config.py | 2 +- tests/test_relations/test_weakref_checking.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ormar/__init__.py b/ormar/__init__.py index 1910b3c69..87f162422 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -23,6 +23,7 @@ from importlib.metadata import version # type: ignore except ImportError: # pragma: no cover from importlib_metadata import version # type: ignore +from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I100 from ormar.decorators import ( # noqa: I100 post_bulk_update, post_delete, @@ -73,9 +74,8 @@ ) # noqa: I100 -from ormar.models import ExcludableItems, Extra, Model +from ormar.models import ExcludableItems, Extra, Model, OrmarConfig from ormar.models.metaclass import ModelMeta -from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I100 from ormar.queryset import OrderAction, QuerySet, and_, or_ from ormar.relations import RelationType from ormar.signals import Signal diff --git a/ormar/fields/__init__.py b/ormar/fields/__init__.py index a9dcd7f2d..53da0277d 100644 --- a/ormar/fields/__init__.py +++ b/ormar/fields/__init__.py @@ -26,9 +26,9 @@ Time, ) from ormar.fields.parsers import DECODERS_MAP, ENCODERS_MAP, SQL_ENCODERS_MAP -from ormar.fields.referential_actions import ReferentialAction from ormar.fields.sqlalchemy_encrypted import EncryptBackend, EncryptBackends from ormar.fields.through_field import Through, ThroughField +from ormar.fields.referential_actions import ReferentialAction __all__ = [ "Decimal", diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index 3920997f3..16b28a6a7 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -4,7 +4,7 @@ import sqlalchemy from sqlalchemy.sql.schema import ColumnCollectionConstraint -from ormar import BaseField, ForeignKeyField, ManyToManyField +from ormar.fields import BaseField, ForeignKeyField, ManyToManyField from ormar.models.helpers import alias_manager from ormar.models.utils import Extra from ormar.queryset.queryset import QuerySet diff --git a/tests/test_relations/test_weakref_checking.py b/tests/test_relations/test_weakref_checking.py index bdd5afc66..2c19f4a18 100644 --- a/tests/test_relations/test_weakref_checking.py +++ b/tests/test_relations/test_weakref_checking.py @@ -35,7 +35,7 @@ class Artist(ormar.Model): def test_weakref_init(): band = Band(name="Band") artist1 = Artist(name="Artist 1", band=band) - Artist(name="Artist 2", band=band) + artist2 = Artist(name="Artist 2", band=band) artist3 = Artist(name="Artist 3", band=band) del artist1 From 8d29c1f9fee47dc55281237ec6ae5df2de6c23ad Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 25 Jan 2024 16:26:08 +0100 Subject: [PATCH 28/95] fix evaluate in py3.8 --- ormar/fields/foreign_key.py | 12 +++++++++++- ormar/fields/many_to_many.py | 5 ++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index 581164ba2..b6c63cbf2 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -1,4 +1,5 @@ import string +import sys import uuid from dataclasses import dataclass from random import choices @@ -361,6 +362,15 @@ def default_source_field_name(self) -> str: prefix = "to_" if self.self_reference else "" return self.through_relation_name or f"{prefix}{self.owner.get_name()}" + def _evaluate_forward_ref(self, globalns: Any, localns: Any, is_through: bool = False) -> None: + target = "through" if is_through else "to" + target_obj = getattr(self, target) + if sys.version_info.minor <= 8: + evaluated = target_obj._evaluate(globalns, localns) + else: + evaluated = target_obj._evaluate(globalns, localns, set()) + setattr(self, target, evaluated) + def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: """ Evaluates the ForwardRef to actual Field based on global and local namespaces @@ -373,7 +383,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = self.to._evaluate(globalns, localns, set()) + self._evaluate_forward_ref(globalns, localns) ( self.__type__, self.constraints, diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index a23ec6c67..d44876453 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -229,8 +229,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: :rtype: None """ if self.to.__class__ == ForwardRef: - self.to = self.to._evaluate(globalns, localns, set()) - + self._evaluate_forward_ref(globalns, localns) ( self.__type__, self.column_type, @@ -241,7 +240,7 @@ def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: self.to_pk_only = pk_only_model if self.through.__class__ == ForwardRef: - self.through = self.through._evaluate(globalns, localns, set()) + self._evaluate_forward_ref(globalns, localns, is_through=True) forbid_through_relations(self.through) From d286de5a8b67393b002231492f623a4d24f75677 Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 25 Jan 2024 19:18:24 +0100 Subject: [PATCH 29/95] partially fix coverage --- Makefile | 2 +- ormar/fields/foreign_key.py | 4 +- ormar/fields/parsers.py | 16 ++++- ormar/fields/sqlalchemy_encrypted.py | 7 ++- ormar/models/descriptors/descriptors.py | 7 +-- ormar/models/helpers/relations.py | 2 +- ormar/models/helpers/validation.py | 60 ------------------- ormar/models/newbasemodel.py | 25 +------- ormar/queryset/field_accessor.py | 9 --- .../test_encryption/test_encrypted_columns.py | 7 +++ .../test_fastapi/test_skip_reverse_models.py | 12 ++-- .../test_model_definition.py | 11 ++++ tests/test_model_definition/test_models.py | 11 +--- 13 files changed, 54 insertions(+), 119 deletions(-) diff --git a/Makefile b/Makefile index 2d80d56af..29fab21d1 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ test: pytest coverage: - pytest --cov=ormar --cov=tests --cov-fail-under=100 --cov-report=term-missing + pytest --cov=ormar --cov=tests --cov-fail-under=100 --cov-report=term-missing tests type_check: mkdir -p .mypy_cache && poetry run python -m mypy . --ignore-missing-imports --install-types --non-interactive diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index b6c63cbf2..f9c75e9b1 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -365,9 +365,9 @@ def default_source_field_name(self) -> str: def _evaluate_forward_ref(self, globalns: Any, localns: Any, is_through: bool = False) -> None: target = "through" if is_through else "to" target_obj = getattr(self, target) - if sys.version_info.minor <= 8: + if sys.version_info.minor <= 8: # pragma: no cover evaluated = target_obj._evaluate(globalns, localns) - else: + else: # pragma: no cover evaluated = target_obj._evaluate(globalns, localns, set()) setattr(self, target, evaluated) diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index dcc3f6cbe..c885e954b 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -31,7 +31,15 @@ def encode_decimal(value: decimal.Decimal, precision: int = None) -> float: return float(value) -def encode_bytes(value: Union[str, bytes], represent_as_string: bool = False) -> bytes: +def encode_bytes(value: Union[str, bytes], represent_as_string: bool = False) -> str: + if represent_as_string: + value = value if isinstance(value, str) else base64.b64encode(value).decode("utf-8") + else: + value = value if isinstance(value, str) else value.decode("utf-8") + return value + + +def decode_bytes(value: str, represent_as_string: bool = False) -> bytes: if represent_as_string: value = value if isinstance(value, bytes) else base64.b64decode(value) else: @@ -74,6 +82,11 @@ def re_dump_value(value: str) -> Union[str, bytes]: SQL_ENCODERS_MAP: Dict[type, Callable] = {bool: encode_bool, **ENCODERS_MAP} +ADDITIONAL_PARAMETERS_MAP: Dict[type, str] = { + bytes: "", + decimal.Decimal: "precision" +} + DECODERS_MAP = { bool: parse_bool, @@ -82,4 +95,5 @@ def re_dump_value(value: str) -> Union[str, bytes]: datetime.time: SchemaValidator(core_schema.time_schema()).validate_python, pydantic.Json: json.loads, decimal.Decimal: decimal.Decimal, + bytes: decode_bytes, } diff --git a/ormar/fields/sqlalchemy_encrypted.py b/ormar/fields/sqlalchemy_encrypted.py index 90518e33a..fe5d92f9c 100644 --- a/ormar/fields/sqlalchemy_encrypted.py +++ b/ormar/fields/sqlalchemy_encrypted.py @@ -162,7 +162,10 @@ def process_bind_param(self, value: Any, dialect: Dialect) -> Optional[str]: except AttributeError: encoder = ormar.SQL_ENCODERS_MAP.get(self.type_, None) if encoder: - value = encoder(value) # type: ignore + if self.type_ == bytes: + value = encoder(value, self._field_type.represent_as_base64_str) + else: + value = encoder(value) # type: ignore encrypted_value = self.backend.encrypt(value) return encrypted_value @@ -177,6 +180,8 @@ def process_result_value(self, value: Any, dialect: Dialect) -> Any: except AttributeError: decoder = ormar.DECODERS_MAP.get(self.type_, None) if decoder: + if self.type_ == bytes: + return decoder(decrypted_value, self._field_type.represent_as_base64_str) return decoder(decrypted_value) # type: ignore return self._field_type.__type__(decrypted_value) # type: ignore diff --git a/ormar/models/descriptors/descriptors.py b/ormar/models/descriptors/descriptors.py index f8ea6043f..ff788edbe 100644 --- a/ormar/models/descriptors/descriptors.py +++ b/ormar/models/descriptors/descriptors.py @@ -1,7 +1,7 @@ import base64 from typing import TYPE_CHECKING, Any, List, Type -from ormar.fields.parsers import encode_json +from ormar.fields.parsers import encode_json, decode_bytes if TYPE_CHECKING: # pragma: no cover from ormar import Model @@ -65,10 +65,7 @@ def __get__(self, instance: "Model", owner: Type["Model"]) -> Any: def __set__(self, instance: "Model", value: Any) -> None: field = instance.ormar_config.model_fields[self.name] if isinstance(value, str): - if field.represent_as_base64_str: - value = base64.b64decode(value) - else: - value = value.encode("utf-8") + value = decode_bytes(value=value, represent_as_string=field.represent_as_base64_str) instance._internal_set(self.name, value) instance.set_save_status(False) diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 8ba7f1a4b..886e05a3b 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -175,7 +175,7 @@ def serialize( try: serialized = handler([child]) except ValueError as exc: - if not str(exc).startswith("Circular reference"): + if not str(exc).startswith("Circular reference"): # pragma: no cover raise exc result.append({child.ormar_config.pkname: child.pk}) else: diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 71129bed2..f3a08adf0 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -21,7 +21,6 @@ import pydantic -import ormar # noqa: I100, I202 from ormar.models.helpers.models import config_field_not_set from ormar.queryset.utils import translate_list_to_dict @@ -30,33 +29,6 @@ from ormar.fields import BaseField -def convert_value_if_needed(field: "BaseField", value: Any) -> Any: - """ - Converts dates to isoformat as fastapi can check this condition in routes - and the fields are not yet parsed. - Converts enums to list of it's values. - Converts uuids to strings. - Converts decimal to float with given scale. - - :param field: ormar field to check with choices - :type field: BaseField - :param value: current values of the model to verify - :type value: Any - :return: value, choices list - :rtype: Any - """ - encoder = ormar.ENCODERS_MAP.get(field.__type__, lambda x: x) - if field.__type__ == decimal.Decimal: - precision = field.scale # type: ignore - value = encoder(value, precision) - elif field.__type__ == bytes: - represent_as_string = field.represent_as_base64_str - value = encoder(value, represent_as_string) - elif encoder: - value = encoder(value) - return value - - def generate_model_example(model: Type["Model"], relation_map: Dict = None) -> Dict: """ Generates example to be included in schema in fastapi. @@ -198,8 +170,6 @@ def overwrite_example_and_description( :type model: Type["Model"] """ schema["example"] = generate_model_example(model=model) - if "Main base class of ormar Model." in schema.get("description", ""): - schema["description"] = f"{model.__name__}" def overwrite_binary_format(schema: Dict[str, Any], model: Type["Model"]) -> None: @@ -218,36 +188,6 @@ def overwrite_binary_format(schema: Dict[str, Any], model: Type["Model"]) -> Non and model.ormar_config.model_fields[field_id].represent_as_base64_str ): prop["format"] = "base64" - if prop.get("enum"): - prop["enum"] = [ - base64.b64encode(choice).decode() for choice in prop.get("enum", []) - ] - - -def construct_modify_schema_function(fields_with_choices: List) -> Callable: - """ - Modifies the schema to include fields with choices validator. - Those fields will be displayed in schema as Enum types with available choices - values listed next to them. - - Note that schema extra has to be a function, otherwise it's called to soon - before all the relations are expanded. - - :param fields_with_choices: list of fields with choices validation - :type fields_with_choices: List - :return: callable that will be run by pydantic to modify the schema - :rtype: Callable - """ - - def schema_extra(schema: Dict[str, Any], model: Type["Model"]) -> None: - for field_id, prop in schema.get("properties", {}).items(): - if field_id in fields_with_choices: - prop["enum"] = list(model.ormar_config.model_fields[field_id].choices) - prop["description"] = prop.get("description", "") + "An enumeration." - overwrite_example_and_description(schema=schema, model=model) - overwrite_binary_format(schema=schema, model=model) - - return staticmethod(schema_extra) # type: ignore def construct_schema_function_without_choices() -> Callable: diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 3ae65a4c9..778862a28 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -26,7 +26,7 @@ from ormar.exceptions import ModelError, ModelPersistenceError from ormar.fields import BaseField from ormar.fields.foreign_key import ForeignKeyField -from ormar.fields.parsers import encode_json +from ormar.fields.parsers import encode_json, decode_bytes from ormar.models.helpers import register_relation_in_alias_manager from ormar.models.helpers.relations import expand_reverse_relationship from ormar.models.helpers.sqlalchemy import ( @@ -425,22 +425,6 @@ def __same__(self, other: "NewBaseModel") -> bool: else: return hash(self) == other.__hash__() - def _copy_and_set_values( - self: "NewBaseModel", values: "DictStrAny", fields_set: "SetStr", *, deep: bool - ) -> "NewBaseModel": - """ - Overwrite related models values with dict representation to avoid infinite - recursion through related fields. - """ - self_dict = values - self_dict.update(self.dict(exclude_list=True)) - return cast( - "NewBaseModel", - super()._copy_and_set_values( - values=self_dict, fields_set=fields_set, deep=deep - ), - ) - @classmethod def get_name(cls, lower: bool = True) -> str: """ @@ -989,11 +973,8 @@ def _convert_to_bytes(self, column_name: str, value: Any) -> Union[str, Dict]: if column_name not in self._bytes_fields: return value field = self.ormar_config.model_fields[column_name] - if not isinstance(value, bytes) and value is not None: - if field.represent_as_base64_str: - value = base64.b64decode(value) - else: - value = value.encode("utf-8") + if value is not None: + value = decode_bytes(value=value, represent_as_string=field.represent_as_base64_str) return value def _convert_bytes_to_str(self, column_name: str, value: Any) -> Union[str, Dict]: diff --git a/ormar/queryset/field_accessor.py b/ormar/queryset/field_accessor.py index 81440e07c..2ff557a21 100644 --- a/ormar/queryset/field_accessor.py +++ b/ormar/queryset/field_accessor.py @@ -26,15 +26,6 @@ def __init__( self._model = model self._access_chain = access_chain - def __bool__(self) -> bool: - """ - Hack to avoid pydantic name check from parent model, returns false - - :return: False - :rtype: bool - """ - return False - def __getattr__(self, item: str) -> Any: """ Accessor return new accessor for each field and nested models. diff --git a/tests/test_encryption/test_encrypted_columns.py b/tests/test_encryption/test_encrypted_columns.py index 01546baf4..35e317c4b 100644 --- a/tests/test_encryption/test_encrypted_columns.py +++ b/tests/test_encryption/test_encrypted_columns.py @@ -69,6 +69,8 @@ class Author(ormar.Model): test_smallint: int = ormar.SmallInteger(default=0, **default_fernet) test_decimal = ormar.Decimal(scale=2, precision=10, **default_fernet) test_decimal2 = ormar.Decimal(max_digits=10, decimal_places=2, **default_fernet) + test_bytes = ormar.LargeBinary(max_length=100, **default_fernet) + test_b64bytes = ormar.LargeBinary(max_length=100, represent_as_base64_str=True, **default_fernet) custom_backend: str = ormar.String( max_length=200, encrypt_secret="asda8", @@ -187,6 +189,8 @@ async def test_save_and_retrieve(): test_decimal2=decimal.Decimal(5.5), test_json=dict(aa=12), custom_backend="test12", + test_bytes=b"test", + test_b64bytes=b"test2" ).save() author = await Author.objects.get() @@ -209,6 +213,9 @@ async def test_save_and_retrieve(): assert author.test_decimal == 3.5 assert author.test_decimal2 == 5.5 assert author.custom_backend == "test12" + assert author.test_bytes == "test".encode("utf-8") + assert author.test_b64bytes == "dGVzdDI=" + assert base64.b64decode(author.test_b64bytes) == b"test2" @pytest.mark.asyncio diff --git a/tests/test_fastapi/test_skip_reverse_models.py b/tests/test_fastapi/test_skip_reverse_models.py index e7a8edb2d..4e879e2ff 100644 --- a/tests/test_fastapi/test_skip_reverse_models.py +++ b/tests/test_fastapi/test_skip_reverse_models.py @@ -74,15 +74,13 @@ def create_test_database(): metadata.drop_all(engine) -@app.post("/categories/", response_model=Category) -async def create_category(category: Category): - await category.save() - await category.save_related(follow=True, save_all=True) - return category +@app.post("/categories/forbid/", response_model=Category2) +async def create_category_forbid(category: Category2): # pragma: no cover + pass -@app.post("/categories/forbid/", response_model=Category2) -async def create_category_forbid(category: Category2): +@app.post("/categories/", response_model=Category) +async def create_category(category: Category): await category.save() await category.save_related(follow=True, save_all=True) return category diff --git a/tests/test_model_definition/test_model_definition.py b/tests/test_model_definition/test_model_definition.py index 82ce8c96b..57fd521c5 100644 --- a/tests/test_model_definition/test_model_definition.py +++ b/tests/test_model_definition/test_model_definition.py @@ -134,6 +134,17 @@ class JsonSample3(ormar.Model): test_json = ormar.JSON(nullable=True) +def test_wrong_pydantic_config(): + with pytest.raises(ModelDefinitionError): + + class ErrorSample(ormar.Model): + model_config = ["test"] + ormar_config = ormar.OrmarConfig(tablename="jsons3") + + id: int = ormar.Integer(primary_key=True) + test_json = ormar.JSON(nullable=True) + + def test_non_existing_attr(example): with pytest.raises(ValueError): example.new_attr = 12 diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index a7f664b38..efdfa6ae9 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -41,7 +41,7 @@ class LargeBinarySample(ormar.Model): ) id: int = ormar.Integer(primary_key=True) - test_binary: bytes = ormar.LargeBinary(max_length=100000, choices=[blob, blob2]) + test_binary: bytes = ormar.LargeBinary(max_length=100000) blob3 = os.urandom(64) @@ -518,15 +518,6 @@ async def test_model_first(): assert await User.objects.order_by("name").first() == jane - -def not_contains(a, b): - return a not in b - - -def contains(a, b): - return a in b - - @pytest.mark.asyncio async def test_model_choices(): """Test that choices work properly for various types of fields.""" From f27c1d59f1d0247af5f9479714b9a6e85bd1824b Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 13:44:47 +0100 Subject: [PATCH 30/95] fix coverage, add more tests --- ormar/__init__.py | 3 +- ormar/fields/__init__.py | 2 +- ormar/fields/parsers.py | 18 +++--- ormar/fields/sqlalchemy_encrypted.py | 11 ++-- ormar/models/descriptors/descriptors.py | 34 ++--------- ormar/models/helpers/relations.py | 14 +---- ormar/models/helpers/validation.py | 6 +- ormar/models/newbasemodel.py | 4 +- .../test_encryption/test_encrypted_columns.py | 4 +- .../test_excluding_subset_of_columns.py | 40 +++++++++++++ tests/test_fastapi/test_fastapi_docs.py | 18 +++++- .../test_populate_default_values.py | 2 + .../test_replacing_models_with_copy.py | 58 +++++++++++++++++++ tests/test_relations/test_weakref_checking.py | 2 +- 14 files changed, 145 insertions(+), 71 deletions(-) create mode 100644 tests/test_relations/test_replacing_models_with_copy.py diff --git a/ormar/__init__.py b/ormar/__init__.py index 87f162422..b25cc4ee9 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -105,7 +105,6 @@ def __repr__(self) -> str: "Float", "ManyToMany", "Model", - "Action", "ModelDefinitionError", "MultipleMatches", "NoMatch", @@ -121,7 +120,6 @@ def __repr__(self) -> str: "QuerySetProtocol", "RelationProtocol", "ModelMeta", - "property_field", "post_bulk_update", "post_delete", "post_save", @@ -147,4 +145,5 @@ def __repr__(self) -> str: "DECODERS_MAP", "LargeBinary", "Extra", + "OrmarConfig", ] diff --git a/ormar/fields/__init__.py b/ormar/fields/__init__.py index 53da0277d..a9dcd7f2d 100644 --- a/ormar/fields/__init__.py +++ b/ormar/fields/__init__.py @@ -26,9 +26,9 @@ Time, ) from ormar.fields.parsers import DECODERS_MAP, ENCODERS_MAP, SQL_ENCODERS_MAP +from ormar.fields.referential_actions import ReferentialAction from ormar.fields.sqlalchemy_encrypted import EncryptBackend, EncryptBackends from ormar.fields.through_field import Through, ThroughField -from ormar.fields.referential_actions import ReferentialAction __all__ = [ "Decimal", diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index c885e954b..f62d2ac97 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -22,13 +22,11 @@ def encode_bool(value: bool) -> str: def encode_decimal(value: decimal.Decimal, precision: int = None) -> float: - if precision: - return ( - round(float(value), precision) - if isinstance(value, decimal.Decimal) - else value - ) - return float(value) + return ( + round(float(value), precision) + if isinstance(value, decimal.Decimal) + else value + ) def encode_bytes(value: Union[str, bytes], represent_as_string: bool = False) -> str: @@ -83,8 +81,8 @@ def re_dump_value(value: str) -> Union[str, bytes]: SQL_ENCODERS_MAP: Dict[type, Callable] = {bool: encode_bool, **ENCODERS_MAP} ADDITIONAL_PARAMETERS_MAP: Dict[type, str] = { - bytes: "", - decimal.Decimal: "precision" + bytes: "represent_as_base64_str", + decimal.Decimal: "decimal_places" } @@ -94,6 +92,6 @@ def re_dump_value(value: str) -> Union[str, bytes]: datetime.date: SchemaValidator(core_schema.date_schema()).validate_python, datetime.time: SchemaValidator(core_schema.time_schema()).validate_python, pydantic.Json: json.loads, - decimal.Decimal: decimal.Decimal, + decimal.Decimal: lambda x, precision: decimal.Decimal(x, context=decimal.Context(prec=precision)), bytes: decode_bytes, } diff --git a/ormar/fields/sqlalchemy_encrypted.py b/ormar/fields/sqlalchemy_encrypted.py index fe5d92f9c..d17e6d761 100644 --- a/ormar/fields/sqlalchemy_encrypted.py +++ b/ormar/fields/sqlalchemy_encrypted.py @@ -10,6 +10,7 @@ import ormar # noqa: I100, I202 from ormar import ModelDefinitionError # noqa: I202, I100 +from ormar.fields.parsers import ADDITIONAL_PARAMETERS_MAP cryptography = None try: # pragma: nocover @@ -162,8 +163,9 @@ def process_bind_param(self, value: Any, dialect: Dialect) -> Optional[str]: except AttributeError: encoder = ormar.SQL_ENCODERS_MAP.get(self.type_, None) if encoder: - if self.type_ == bytes: - value = encoder(value, self._field_type.represent_as_base64_str) + if self.type_ in ADDITIONAL_PARAMETERS_MAP: + additional_parameter = getattr(self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_]) + value = encoder(value, additional_parameter) else: value = encoder(value) # type: ignore @@ -180,8 +182,9 @@ def process_result_value(self, value: Any, dialect: Dialect) -> Any: except AttributeError: decoder = ormar.DECODERS_MAP.get(self.type_, None) if decoder: - if self.type_ == bytes: - return decoder(decrypted_value, self._field_type.represent_as_base64_str) + if self.type_ in ADDITIONAL_PARAMETERS_MAP: + additional_parameter = getattr(self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_]) + return decoder(decrypted_value, additional_parameter) return decoder(decrypted_value) # type: ignore return self._field_type.__type__(decrypted_value) # type: ignore diff --git a/ormar/models/descriptors/descriptors.py b/ormar/models/descriptors/descriptors.py index ff788edbe..92866a898 100644 --- a/ormar/models/descriptors/descriptors.py +++ b/ormar/models/descriptors/descriptors.py @@ -1,7 +1,7 @@ import base64 -from typing import TYPE_CHECKING, Any, List, Type +from typing import TYPE_CHECKING, Any, Type -from ormar.fields.parsers import encode_json, decode_bytes +from ormar.fields.parsers import decode_bytes, encode_json if TYPE_CHECKING: # pragma: no cover from ormar import Model @@ -104,39 +104,13 @@ def __get__(self, instance: "Model", owner: Type["Model"]) -> Any: return None # pragma no cover def __set__(self, instance: "Model", value: Any) -> None: - model = instance.ormar_config.model_fields[self.name].expand_relationship( + instance.ormar_config.model_fields[self.name].expand_relationship( value=value, child=instance ) - if isinstance(instance.__dict__.get(self.name), list): - # virtual foreign key or many to many - # TODO: Fix double items in dict, no effect on real action just ugly repr - self._populate_models_dict_if_not_present(instance=instance, model=model) - else: - # foreign key relation - instance.__dict__[self.name] = model + if not isinstance(instance.__dict__.get(self.name), list): instance.set_save_status(False) - def _populate_models_dict_if_not_present( - self, instance: "Model", model: Any - ) -> None: - models = instance.__dict__[self.name] - if isinstance(model, list): - for model_ in model: - self._append_to_list_if_not_present(models=models, model=model_) - return - - self._append_to_list_if_not_present(models=models, model=model) - - @staticmethod - def _append_to_list_if_not_present(models: List["Model"], model: Any) -> None: - try: - if model not in models: - models.append(model) - except ReferenceError: - models.clear() - models.append(model) - class PropertyDescriptor: """ diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 886e05a3b..e43c57d68 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -172,14 +172,8 @@ def serialize( result = [] for child in children: - try: - serialized = handler([child]) - except ValueError as exc: - if not str(exc).startswith("Circular reference"): # pragma: no cover - raise exc - result.append({child.ormar_config.pkname: child.pk}) - else: - result.append(serialized) + # If there is one circular ref dump all children as pk only + result.append({child.ormar_config.pkname: child.pk}) return result decorator = field_serializer(related_name, mode="wrap", check_fields=False)( @@ -204,7 +198,7 @@ def replace_models_with_copy( return create_copy_to_avoid_circular_references( model=annotation, source_model_field=source_model_field ) - elif hasattr(annotation, "__origin__"): + elif hasattr(annotation, "__origin__") and annotation.__origin__ in {list, Union}: if annotation.__origin__ == list: return List[ replace_models_with_copy( @@ -221,8 +215,6 @@ def replace_models_with_copy( for arg in args ] return Union[tuple(new_args)] - else: - return annotation else: return annotation diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index f3a08adf0..493805997 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -1,4 +1,3 @@ -import base64 import decimal import numbers from typing import ( @@ -122,10 +121,7 @@ def generate_pydantic_example( for name in name_to_check: field = pydantic_model.model_fields[name] type_ = field.annotation - if typing.get_origin(type_) is list: - example[name] = [get_pydantic_example_repr(type_)] - else: - example[name] = get_pydantic_example_repr(type_) + example[name] = get_pydantic_example_repr(type_) return example diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 778862a28..2596c5c24 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -26,7 +26,7 @@ from ormar.exceptions import ModelError, ModelPersistenceError from ormar.fields import BaseField from ormar.fields.foreign_key import ForeignKeyField -from ormar.fields.parsers import encode_json, decode_bytes +from ormar.fields.parsers import decode_bytes, encode_json from ormar.models.helpers import register_relation_in_alias_manager from ormar.models.helpers.relations import expand_reverse_relationship from ormar.models.helpers.sqlalchemy import ( @@ -768,7 +768,7 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 dict_instance[field] = model_dict else: dict_instance[field] = None - except ReferenceError: + except ReferenceError: # pragma: no cover dict_instance[field] = None return dict_instance diff --git a/tests/test_encryption/test_encrypted_columns.py b/tests/test_encryption/test_encrypted_columns.py index 35e317c4b..7d9745d0b 100644 --- a/tests/test_encryption/test_encrypted_columns.py +++ b/tests/test_encryption/test_encrypted_columns.py @@ -185,7 +185,7 @@ async def test_save_and_retrieve(): uuid_test=test_uuid, test_float=1.2, test_bool=True, - test_decimal=decimal.Decimal(3.5), + test_decimal=3.57, test_decimal2=decimal.Decimal(5.5), test_json=dict(aa=12), custom_backend="test12", @@ -210,7 +210,7 @@ async def test_save_and_retrieve(): assert author.test_float2 is None assert author.test_bigint == 0 assert author.test_json == {"aa": 12} - assert author.test_decimal == 3.5 + assert float(author.test_decimal) == 3.57 assert author.test_decimal2 == 5.5 assert author.custom_backend == "test12" assert author.test_bytes == "test".encode("utf-8") diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index 860ac519b..0e8c4a85b 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -180,3 +180,43 @@ async def test_selecting_subset(): await Car.objects.select_related("manufacturer").exclude_fields( ["manufacturer__name"] ).all() + + +@pytest.mark.asyncio +async def test_excluding_nested_lists_in_dump(): + async with database: + async with database.transaction(force_rollback=True): + toyota = await Company.objects.create(name="Toyota", founded=1937) + await Car.objects.create( + manufacturer=toyota, + name="Corolla", + year=2020, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", + ) + await Car.objects.create( + manufacturer=toyota, + name="Yaris", + year=2019, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", + ) + manufacturer = await Company.objects.select_related("cars").get(name="Toyota") + assert manufacturer.dict() == {'cars': [{'aircon_type': 'Manual', + 'gearbox_type': 'Manual', + 'gears': 5, + 'id': 1, + 'name': 'Corolla', + 'year': 2020}, + {'aircon_type': 'Manual', + 'gearbox_type': 'Manual', + 'gears': 5, + 'id': 2, + 'name': 'Yaris', + 'year': 2019}], + 'founded': 1937, + 'id': 1, + 'name': 'Toyota'} + assert manufacturer.dict(exclude_list=True) == {'founded': 1937, 'id': 1, 'name': 'Toyota'} diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index ed4bd291f..fd63dd578 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -1,7 +1,9 @@ import datetime -from typing import List, Optional +from typing import List, Optional, Union import databases +from pydantic import Field + import ormar import pydantic import pytest @@ -62,7 +64,8 @@ class Item(ormar.Model): id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) pydantic_int: Optional[int] = None - test_P: Optional[List[PTestP]] = None + test_P: List[PTestP] = Field(default_factory=list) + test_P_or_A: Union[int, str] = None categories = ormar.ManyToMany(Category) @@ -77,6 +80,8 @@ def create_test_database(): @app.get("/items/", response_model=List[Item]) async def get_items(): items = await Item.objects.select_related("categories").all() + for item in items: + item.test_P_or_A = 2 return items @@ -103,17 +108,21 @@ async def test_all_endpoints(): client = AsyncClient(app=app, base_url="http://testserver") async with client as client, LifespanManager(app): response = await client.post("/categories/", json={"name": "test cat"}) + assert response.status_code == 200 category = response.json() response = await client.post("/categories/", json={"name": "test cat2"}) + assert response.status_code == 200 category2 = response.json() - response = await client.post("/items/", json={"name": "test", "id": 1}) + response = await client.post("/items/", json={"name": "test", "id": 1, "test_P_or_A": 0}) + assert response.status_code == 200 item = Item(**response.json()) assert item.pk is not None response = await client.post( "/items/add_category/", json={"item": item.dict(), "category": category} ) + assert response.status_code == 200 item = Item(**response.json()) assert len(item.categories) == 1 assert item.categories[0].name == "test cat" @@ -123,6 +132,7 @@ async def test_all_endpoints(): ) response = await client.get("/items/") + assert response.status_code == 200 items = [Item(**item) for item in response.json()] assert items[0] == item assert len(items[0].categories) == 2 @@ -146,6 +156,7 @@ def test_schema_modification(): "name": "string", "pydantic_int": 0, "test_P": [{"a": 0, "b": {"c": "string", "d": "string", "e": "string"}}], + 'test_P_or_A': (0, 'string') } schema = Category.model_json_schema() @@ -160,6 +171,7 @@ def test_schema_modification(): "test_P": [ {"a": 0, "b": {"c": "string", "d": "string", "e": "string"}} ], + 'test_P_or_A': (0, 'string') } ], } diff --git a/tests/test_model_methods/test_populate_default_values.py b/tests/test_model_methods/test_populate_default_values.py index 92de8528d..1ae5ba802 100644 --- a/tests/test_model_methods/test_populate_default_values.py +++ b/tests/test_model_methods/test_populate_default_values.py @@ -25,6 +25,7 @@ class Task(ormar.Model): points: int = ormar.Integer( default=0, minimum=0, server_default=text("0"), nullable=False ) + score: int = ormar.Integer(default=5) def test_populate_default_values(): @@ -38,3 +39,4 @@ def test_populate_default_values(): assert result["id"] is None assert result["name"] == "" assert result["points"] == 0 + assert result["score"] == 5 diff --git a/tests/test_relations/test_replacing_models_with_copy.py b/tests/test_relations/test_replacing_models_with_copy.py new file mode 100644 index 000000000..8d905d2e4 --- /dev/null +++ b/tests/test_relations/test_replacing_models_with_copy.py @@ -0,0 +1,58 @@ +from typing import Any, Dict, Optional, Tuple, Union + +import databases +import ormar +import pytest +import sqlalchemy + +from tests.settings import DATABASE_URL + +database = databases.Database(DATABASE_URL, force_rollback=True) +metadata = sqlalchemy.MetaData() + + +class Album(ormar.Model): + ormar_config = ormar.OrmarConfig( + tablename="albums", + metadata=metadata, + database=database, + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + is_best_seller: bool = ormar.Boolean(default=False) + properties: Tuple[str, Any] + score: Union[str, int] + + +class Track(ormar.Model): + ormar_config = ormar.OrmarConfig( + tablename="tracks", + metadata=metadata, + database=database, + ) + + id: int = ormar.Integer(primary_key=True) + album: Optional[Album] = ormar.ForeignKey(Album) + title: str = ormar.String(max_length=100) + position: int = ormar.Integer() + play_count: int = ormar.Integer(nullable=True, default=0) + is_disabled: bool = ormar.Boolean(default=False) + properties: Tuple[str, Any] + + +@pytest.fixture(autouse=True, scope="module") +def create_test_database(): + engine = sqlalchemy.create_engine(DATABASE_URL) + metadata.drop_all(engine) + metadata.create_all(engine) + yield + metadata.drop_all(engine) + + +@pytest.mark.asyncio +async def test_model_is_replaced_by_a_copy(): + assert Album.model_fields["tracks"].annotation.__args__[1] != Track + assert Album.model_fields["tracks"].annotation.__args__[1].model_fields.keys() == Track.model_fields.keys() + + diff --git a/tests/test_relations/test_weakref_checking.py b/tests/test_relations/test_weakref_checking.py index 2c19f4a18..b246e0502 100644 --- a/tests/test_relations/test_weakref_checking.py +++ b/tests/test_relations/test_weakref_checking.py @@ -47,4 +47,4 @@ def test_weakref_init(): band.artists # Force it to clean assert len(band.artists) == 1 - assert band.artists[0].name == "Artist 2" + assert band.artists[0].name == artist2.name From 8c75752e9ce955a0b2bc7bbe11980a9bcfb34414 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 13:50:51 +0100 Subject: [PATCH 31/95] fix test ids --- .../test_excluding_subset_of_columns.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index 0e8c4a85b..3550d83e8 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -187,7 +187,7 @@ async def test_excluding_nested_lists_in_dump(): async with database: async with database.transaction(force_rollback=True): toyota = await Company.objects.create(name="Toyota", founded=1937) - await Car.objects.create( + car1 = await Car.objects.create( manufacturer=toyota, name="Corolla", year=2020, @@ -195,7 +195,7 @@ async def test_excluding_nested_lists_in_dump(): gears=5, aircon_type="Manual", ) - await Car.objects.create( + car2 = await Car.objects.create( manufacturer=toyota, name="Yaris", year=2019, @@ -207,16 +207,16 @@ async def test_excluding_nested_lists_in_dump(): assert manufacturer.dict() == {'cars': [{'aircon_type': 'Manual', 'gearbox_type': 'Manual', 'gears': 5, - 'id': 1, + 'id': car1.id, 'name': 'Corolla', 'year': 2020}, {'aircon_type': 'Manual', 'gearbox_type': 'Manual', 'gears': 5, - 'id': 2, + 'id': car2.id, 'name': 'Yaris', 'year': 2019}], 'founded': 1937, - 'id': 1, + 'id': toyota.id, 'name': 'Toyota'} assert manufacturer.dict(exclude_list=True) == {'founded': 1937, 'id': 1, 'name': 'Toyota'} From 444d418286845c42308bbe9ddd4ece7546584c27 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 13:51:15 +0100 Subject: [PATCH 32/95] fix test ids --- .../test_excluding_subset_of_columns.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index 3550d83e8..14343aedb 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -219,4 +219,4 @@ async def test_excluding_nested_lists_in_dump(): 'founded': 1937, 'id': toyota.id, 'name': 'Toyota'} - assert manufacturer.dict(exclude_list=True) == {'founded': 1937, 'id': 1, 'name': 'Toyota'} + assert manufacturer.dict(exclude_list=True) == {'founded': 1937, 'id': toyota.id, 'name': 'Toyota'} From e090dc4871902089ca5f34a3095156b4fd4a8968 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 18:47:47 +0100 Subject: [PATCH 33/95] fix lint, fix docs, make docs fully working scripts, add test docs job --- .github/workflows/lint.yml | 2 + .github/workflows/test_docs.yml | 31 +++ Makefile | 8 +- benchmarks/conftest.py | 9 +- docs/models/index.md | 10 +- docs/mypy.md | 10 +- docs_src/aggregations/docs001.py | 11 +- docs_src/fastapi/docs001.py | 16 +- docs_src/fastapi/mypy/docs001.py | 7 +- docs_src/fields/docs001.py | 38 ++-- docs_src/fields/docs002.py | 15 +- docs_src/fields/docs003.py | 14 +- docs_src/fields/docs004.py | 8 +- docs_src/models/docs001.py | 7 +- docs_src/models/docs002.py | 10 +- docs_src/models/docs003.py | 9 +- docs_src/models/docs004.py | 19 +- docs_src/models/docs005.py | 180 +++++++++++++----- docs_src/models/docs006.py | 9 +- docs_src/models/docs007.py | 25 ++- docs_src/models/docs008.py | 13 +- docs_src/models/docs009.py | 25 ++- docs_src/models/docs010.py | 35 +++- docs_src/models/docs011.py | 19 -- docs_src/models/docs012.py | 7 +- docs_src/models/docs013.py | 24 +-- docs_src/models/docs014.py | 7 +- docs_src/models/docs015.py | 10 +- docs_src/models/docs016.py | 10 +- docs_src/models/docs017.py | 9 +- docs_src/models/docs018.py | 11 +- docs_src/queries/docs001.py | 17 +- docs_src/queries/docs002.py | 40 ++-- docs_src/queries/docs003.py | 48 +++-- docs_src/queries/docs004.py | 40 ++-- docs_src/queries/docs005.py | 44 +++-- docs_src/queries/docs006.py | 78 ++++---- docs_src/queries/docs007.py | 46 +++-- docs_src/queries/docs008.py | 158 ++++++++------- docs_src/queries/docs009.py | 99 +++++++--- docs_src/relations/docs001.py | 14 +- docs_src/relations/docs002.py | 22 +-- docs_src/relations/docs003.py | 21 +- docs_src/relations/docs004.py | 20 +- docs_src/signals/docs002.py | 50 +++-- docs_src/test_all_docs.py | 22 +++ examples/__init__.py | 3 + examples/fastapi_quick_start.py | 17 +- examples/script_from_readme.py | 10 +- examples/utils.py | 21 ++ ormar/__init__.py | 3 +- ormar/decorators/__init__.py | 1 + ormar/fields/__init__.py | 1 + ormar/fields/foreign_key.py | 6 +- ormar/fields/many_to_many.py | 4 +- ormar/fields/model_fields.py | 18 +- ormar/fields/parsers.py | 14 +- ormar/fields/referential_actions.py | 1 - ormar/fields/sqlalchemy_encrypted.py | 15 +- ormar/models/descriptors/descriptors.py | 4 +- ormar/models/helpers/pydantic.py | 10 +- ormar/models/helpers/relations.py | 25 +-- ormar/models/helpers/validation.py | 8 +- ormar/models/metaclass.py | 14 +- ormar/models/mixins/__init__.py | 1 + ormar/models/newbasemodel.py | 14 +- ormar/models/quick_access_views.py | 1 + ormar/protocols/queryset_protocol.py | 53 ++---- ormar/protocols/relation_protocol.py | 6 +- ormar/queryset/__init__.py | 1 + ormar/queryset/queryset.py | 8 +- ormar/relations/__init__.py | 1 + ormar/signals/__init__.py | 1 + poetry.lock | 48 ++--- pyproject.toml | 1 + scripts/test_docs.sh | 12 ++ tests/test_deferred/test_same_table_joins.py | 3 +- .../test_encryption/test_encrypted_columns.py | 6 +- .../test_complex_relation_tree_performance.py | 31 +-- .../test_excluding_nested_models_lists.py | 0 .../test_excluding_subset_of_columns.py | 48 +++-- tests/test_fastapi/test_fastapi_docs.py | 11 +- .../test_inheritance_concrete_fastapi.py | 2 +- .../test_inheritance_mixins_fastapi.py | 2 +- tests/test_model_definition/test_models.py | 1 + .../test_overwriting_pydantic_field_type.py | 4 +- .../test_replacing_models_with_copy.py | 9 +- 87 files changed, 1071 insertions(+), 695 deletions(-) create mode 100644 .github/workflows/test_docs.yml delete mode 100644 docs_src/models/docs011.py create mode 100644 docs_src/test_all_docs.py create mode 100644 examples/__init__.py create mode 100644 examples/utils.py create mode 100644 scripts/test_docs.sh create mode 100644 tests/test_exclude_include_dict/test_excluding_nested_models_lists.py diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 327d9ff32..28b42d7c2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,5 +27,7 @@ jobs: poetry install --extras "all" env: POETRY_VIRTUALENVS_CREATE: false + - name: Format + run: python -m black . - name: Lint run: python -m ruff . --fix diff --git a/.github/workflows/test_docs.yml b/.github/workflows/test_docs.yml new file mode 100644 index 000000000..87e0b26b7 --- /dev/null +++ b/.github/workflows/test_docs.yml @@ -0,0 +1,31 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: test_docs + +on: + push: + branches-ignore: + - 'gh-pages' + pull_request: + branches: [ master ] + +jobs: + tests_docs: + name: "Python ${{ matrix.python-version }}" + runs-on: ubuntu-latest + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'collerek/ormar' + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install poetry==1.4.2 + poetry install --extras "all" + env: + POETRY_VIRTUALENVS_CREATE: false + - name: Test docs + run: bash scripts/test_docs.sh diff --git a/Makefile b/Makefile index 29fab21d1..8f98fe716 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,9 @@ test_mysql: test_sqlite: bash scripts/test.sh -svv +test_docs: + bash scripts/test_docs.sh -svv + test: pytest @@ -25,4 +28,7 @@ type_check: mkdir -p .mypy_cache && poetry run python -m mypy . --ignore-missing-imports --install-types --non-interactive lint: - poetry run python -m ruff . --fix \ No newline at end of file + poetry run python -m ruff . --fix + +fmt: + poetry run python -m black . \ No newline at end of file diff --git a/benchmarks/conftest.py b/benchmarks/conftest.py index 2795db52d..7338a3b16 100644 --- a/benchmarks/conftest.py +++ b/benchmarks/conftest.py @@ -26,8 +26,7 @@ class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -41,8 +40,7 @@ class AuthorWithManyFields(Author): class Publisher(ormar.Model): - class Meta(BaseMeta): - tablename = "publishers" + ormar_config = base_ormar_config.copy(tablename="publishers") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -50,8 +48,7 @@ class Meta(BaseMeta): class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) author: Author = ormar.ForeignKey(Author, index=True) diff --git a/docs/models/index.md b/docs/models/index.md index 1f891a4b3..3f1437575 100644 --- a/docs/models/index.md +++ b/docs/models/index.md @@ -306,15 +306,7 @@ book = await Book.objects.first_or_404(name="123") ### Type Hints & Legacy -Before version 0.4.0 `ormar` supported only one way of defining `Fields` on a `Model` using python type hints as pydantic. - -```Python hl_lines="15-17" ---8<-- "../docs_src/models/docs011.py" -``` - -But that didn't play well with static type checkers like `mypy` and `pydantic` PyCharm plugin. - -Therefore from version >=0.4.0 `ormar` switched to new notation. +From version >=0.4.0 `ormar` switched to new notation. ```Python hl_lines="15-17" --8<-- "../docs_src/models/docs001.py" diff --git a/docs/mypy.md b/docs/mypy.md index 4066e3d52..d1f13f005 100644 --- a/docs/mypy.md +++ b/docs/mypy.md @@ -1,14 +1,6 @@ To provide better errors check you should use mypy with pydantic [plugin][plugin] -Note that legacy model declaration type will raise static type analyzers errors. - -So you **cannot use the old notation** like this: - -```Python hl_lines="15-17" ---8<-- "../docs_src/models/docs011.py" -``` - -Instead switch to notation introduced in version 0.4.0. +Please use notation introduced in version 0.4.0. ```Python hl_lines="15-17" --8<-- "../docs_src/models/docs012.py" diff --git a/docs_src/aggregations/docs001.py b/docs_src/aggregations/docs001.py index 36f81447c..c92b45910 100644 --- a/docs_src/aggregations/docs001.py +++ b/docs_src/aggregations/docs001.py @@ -16,18 +16,17 @@ class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" - order_by = ["-name"] + ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"]) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" - order_by = ["year", "-ranking"] + + ormar_config = base_ormar_config.copy( + tablename="books", order_by=["year", "-ranking"] + ) id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) diff --git a/docs_src/fastapi/docs001.py b/docs_src/fastapi/docs001.py index fc38cef13..75ba527ae 100644 --- a/docs_src/fastapi/docs001.py +++ b/docs_src/fastapi/docs001.py @@ -5,6 +5,12 @@ import sqlalchemy from fastapi import FastAPI +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) + app = FastAPI() metadata = sqlalchemy.MetaData() database = databases.Database("sqlite:///test.db") @@ -26,20 +32,14 @@ async def shutdown() -> None: class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="items") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/fastapi/mypy/docs001.py b/docs_src/fastapi/mypy/docs001.py index ddc0d5b9d..47b87a073 100644 --- a/docs_src/fastapi/mypy/docs001.py +++ b/docs_src/fastapi/mypy/docs001.py @@ -7,9 +7,10 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id = ormar.Integer(primary_key=True) name = ormar.String(max_length=100) diff --git a/docs_src/fields/docs001.py b/docs_src/fields/docs001.py index ad67cf1e6..3d17a3067 100644 --- a/docs_src/fields/docs001.py +++ b/docs_src/fields/docs001.py @@ -1,26 +1,27 @@ +import asyncio from typing import Optional import databases import ormar import sqlalchemy +from examples import create_drop_database -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar_base_config.copy(tablename="departments") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -28,12 +29,17 @@ class Meta: department: Optional[Department] = ormar.ForeignKey(Department) -department = await Department(name="Science").save() -course = Course(name="Math", completed=False, department=department) +@create_drop_database(base_config=ormar_base_config) +async def verify(): + department = await Department(name="Science").save() + course = Course(name="Math", completed=False, department=department) + print(department.courses[0]) + # Will produce: + # Course(id=None, + # name='Math', + # completed=False, + # department=Department(id=None, name='Science')) + await course.save() + -print(department.courses[0]) -# Will produce: -# Course(id=None, -# name='Math', -# completed=False, -# department=Department(id=None, name='Science')) +asyncio.run(verify()) diff --git a/docs_src/fields/docs002.py b/docs_src/fields/docs002.py index f9ac2394d..505eef0c5 100644 --- a/docs_src/fields/docs002.py +++ b/docs_src/fields/docs002.py @@ -4,23 +4,22 @@ import ormar import sqlalchemy -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/fields/docs003.py b/docs_src/fields/docs003.py index 8390a649c..cfd5836e5 100644 --- a/docs_src/fields/docs003.py +++ b/docs_src/fields/docs003.py @@ -9,18 +9,20 @@ class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/fields/docs004.py b/docs_src/fields/docs004.py index 0d155af3a..cb70a2a68 100644 --- a/docs_src/fields/docs004.py +++ b/docs_src/fields/docs004.py @@ -10,10 +10,10 @@ class Product(ormar.Model): - class Meta: - tablename = "product" - metadata = metadata - database = database + + ormar_config = ormar.OrmarConfig( + database=database, metadata=metadata, tablename="product" + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/models/docs001.py b/docs_src/models/docs001.py index 2d3fe1fd8..c93c767e7 100644 --- a/docs_src/models/docs001.py +++ b/docs_src/models/docs001.py @@ -7,9 +7,10 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/models/docs002.py b/docs_src/models/docs002.py index 995a960b7..87a72cdf1 100644 --- a/docs_src/models/docs002.py +++ b/docs_src/models/docs002.py @@ -7,12 +7,14 @@ class Course(ormar.Model): - class Meta: + + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, # if you omit this parameter it will be created automatically # as class.__name__.lower()+'s' -> "courses" in this example - tablename = "my_courses" - database = database - metadata = metadata + tablename="my_courses", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/models/docs003.py b/docs_src/models/docs003.py index 917fd73ea..c5b7ff386 100644 --- a/docs_src/models/docs003.py +++ b/docs_src/models/docs003.py @@ -7,16 +7,17 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) completed: bool = ormar.Boolean(default=False) -print(Course.__fields__) +print(Course.model_fields) """ Will produce: {'id': Field(name='id', diff --git a/docs_src/models/docs004.py b/docs_src/models/docs004.py index 3a4eac4a5..0d714e9ec 100644 --- a/docs_src/models/docs004.py +++ b/docs_src/models/docs004.py @@ -2,16 +2,19 @@ import ormar import sqlalchemy -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Course(ormar.Model): - class Meta( - ormar.ModelMeta - ): # note you don't have to subclass - but it's recommended for ide completion and mypy - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + tablename="courses", + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -21,5 +24,5 @@ class Meta( print(Course.ormar_config.table.columns) """ Will produce: -['courses.id', 'courses.name', 'courses.completed'] +ImmutableColumnCollection(courses.id, courses.name, courses.completed) """ diff --git a/docs_src/models/docs005.py b/docs_src/models/docs005.py index 2cc2b5f87..e34bed14b 100644 --- a/docs_src/models/docs005.py +++ b/docs_src/models/docs005.py @@ -1,3 +1,5 @@ +import pprint + import databases import ormar import sqlalchemy @@ -7,60 +9,142 @@ class Course(ormar.Model): - class Meta(ormar.ModelMeta): - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) completed: bool = ormar.Boolean(default=False) -print({x: v.__dict__ for x, v in Course.ormar_config.model_fields.items()}) +pprint.pp({x: v.__dict__ for x, v in Course.ormar_config.model_fields.items()}) """ Will produce: -{'completed': mappingproxy({'autoincrement': False, - 'choices': set(), - 'column_type': Boolean(), - 'default': False, - 'index': False, - 'name': 'completed', - 'nullable': True, - 'primary_key': False, - 'pydantic_only': False, - 'server_default': None, - 'unique': False}), - 'id': mappingproxy({'autoincrement': True, - 'choices': set(), - 'column_type': Integer(), - 'default': None, - 'ge': None, - 'index': False, - 'le': None, - 'maximum': None, - 'minimum': None, - 'multiple_of': None, - 'name': 'id', - 'nullable': False, - 'primary_key': True, - 'pydantic_only': False, - 'server_default': None, - 'unique': False}), - 'name': mappingproxy({'allow_blank': False, - 'autoincrement': False, - 'choices': set(), - 'column_type': String(max_length=100), - 'curtail_length': None, - 'default': None, - 'index': False, - 'max_length': 100, - 'min_length': None, - 'name': 'name', - 'nullable': False, - 'primary_key': False, - 'pydantic_only': False, - 'regex': None, - 'server_default': None, - 'strip_whitespace': False, - 'unique': False})} +{'id': {'__type__': , + '__pydantic_type__': , + '__sample__': 0, + 'related_name': None, + 'column_type': Integer(), + 'constraints': [], + 'name': 'id', + 'db_alias': None, + 'primary_key': True, + 'autoincrement': True, + 'nullable': True, + 'sql_nullable': False, + 'index': False, + 'unique': False, + 'pydantic_only': False, + 'choices': False, + 'virtual': None, + 'is_multi': None, + 'is_relation': None, + 'is_through': False, + 'through_relation_name': None, + 'through_reverse_relation_name': None, + 'skip_reverse': False, + 'skip_field': False, + 'owner': , + 'to': None, + 'to_pk_only': None, + 'through': None, + 'self_reference': False, + 'self_reference_primary': None, + 'orders_by': None, + 'related_orders_by': None, + 'encrypt_secret': None, + 'encrypt_backend': , + 'encrypt_custom_backend': None, + 'ormar_default': None, + 'server_default': None, + 'comment': None, + 'represent_as_base64_str': False, + 'minimum': None, + 'maximum': None, + 'multiple_of': None, + 'ge': None, + 'le': None}, + 'name': {'__type__': , + '__pydantic_type__': , + '__sample__': 'string', + 'related_name': None, + 'column_type': String(length=100), + 'constraints': [], + 'name': 'name', + 'db_alias': None, + 'primary_key': False, + 'autoincrement': False, + 'nullable': False, + 'sql_nullable': False, + 'index': False, + 'unique': False, + 'pydantic_only': False, + 'choices': False, + 'virtual': None, + 'is_multi': None, + 'is_relation': None, + 'is_through': False, + 'through_relation_name': None, + 'through_reverse_relation_name': None, + 'skip_reverse': False, + 'skip_field': False, + 'owner': , + 'to': None, + 'to_pk_only': None, + 'through': None, + 'self_reference': False, + 'self_reference_primary': None, + 'orders_by': None, + 'related_orders_by': None, + 'encrypt_secret': None, + 'encrypt_backend': , + 'encrypt_custom_backend': None, + 'ormar_default': None, + 'server_default': None, + 'comment': None, + 'represent_as_base64_str': False, + 'max_length': 100, + 'min_length': None, + 'regex': None}, + 'completed': {'__type__': , + '__pydantic_type__': , + '__sample__': True, + 'related_name': None, + 'column_type': Boolean(), + 'constraints': [], + 'name': 'completed', + 'db_alias': None, + 'primary_key': False, + 'autoincrement': False, + 'nullable': True, + 'sql_nullable': True, + 'index': False, + 'unique': False, + 'pydantic_only': False, + 'choices': False, + 'virtual': None, + 'is_multi': None, + 'is_relation': None, + 'is_through': False, + 'through_relation_name': None, + 'through_reverse_relation_name': None, + 'skip_reverse': False, + 'skip_field': False, + 'owner': , + 'to': None, + 'to_pk_only': None, + 'through': None, + 'self_reference': False, + 'self_reference_primary': None, + 'orders_by': None, + 'related_orders_by': None, + 'encrypt_secret': None, + 'encrypt_backend': , + 'encrypt_custom_backend': None, + 'ormar_default': False, + 'server_default': None, + 'comment': None, + 'represent_as_base64_str': False}} """ diff --git a/docs_src/models/docs006.py b/docs_src/models/docs006.py index b9b24eef7..91b9a7726 100644 --- a/docs_src/models/docs006.py +++ b/docs_src/models/docs006.py @@ -7,13 +7,14 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, # define your constraints in Meta class of the model # it's a list that can contain multiple constraints # hera a combination of name and column will have to be unique in db - constraints = [ormar.UniqueColumns("name", "completed")] + constraints=[ormar.UniqueColumns("name", "completed")], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/models/docs007.py b/docs_src/models/docs007.py index 6e2bcda98..ed408cc9f 100644 --- a/docs_src/models/docs007.py +++ b/docs_src/models/docs007.py @@ -1,22 +1,31 @@ +import asyncio + import databases import ormar import sqlalchemy +from examples import create_drop_database + +DATABASE_URL = "sqlite:///test.db" -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar_base_config.copy(tablename="courses") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) completed: bool = ormar.Boolean(default=False) -course = Course(name="Painting for dummies", completed=False) -await course.save() +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + course = Course(name="Painting for dummies", completed=False) + await course.save() + + await Course.objects.create(name="Painting for dummies", completed=False) + -await Course.objects.create(name="Painting for dummies", completed=False) +asyncio.run(run_query()) diff --git a/docs_src/models/docs008.py b/docs_src/models/docs008.py index faaafc7a2..0fe87a6c2 100644 --- a/docs_src/models/docs008.py +++ b/docs_src/models/docs008.py @@ -2,15 +2,18 @@ import ormar import sqlalchemy -database = databases.Database("sqlite:///test.db", force_rollback=True) +DATABASE_URl = "sqlite:///test.db" + +database = databases.Database(DATABASE_URl, force_rollback=True) metadata = sqlalchemy.MetaData() class Child(ormar.Model): - class Meta: - tablename = "children" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="children", + ) id: int = ormar.Integer(name="child_id", primary_key=True) first_name: str = ormar.String(name="fname", max_length=100) diff --git a/docs_src/models/docs009.py b/docs_src/models/docs009.py index 328e315e4..9f7b753d8 100644 --- a/docs_src/models/docs009.py +++ b/docs_src/models/docs009.py @@ -4,17 +4,30 @@ import ormar import sqlalchemy -from .docs010 import Artist # previous example - database = databases.Database("sqlite:///test.db", force_rollback=True) metadata = sqlalchemy.MetaData() +class Artist(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="artists", + ) + + id: int = ormar.Integer(name="artist_id", primary_key=True) + first_name: str = ormar.String(name="fname", max_length=100) + last_name: str = ormar.String(name="lname", max_length=100) + born_year: int = ormar.Integer(name="year") + + class Album(ormar.Model): - class Meta: - tablename = "music_albums" - metadata = metadata - database = database + + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="music_albums", + ) id: int = ormar.Integer(name="album_id", primary_key=True) name: str = ormar.String(name="album_name", max_length=100) diff --git a/docs_src/models/docs010.py b/docs_src/models/docs010.py index 9bf904a51..63cb712c0 100644 --- a/docs_src/models/docs010.py +++ b/docs_src/models/docs010.py @@ -2,24 +2,39 @@ import ormar import sqlalchemy -from .docs008 import Child +DATABASE_URl = "sqlite:///test.db" -database = databases.Database("sqlite:///test.db", force_rollback=True) +database = databases.Database(DATABASE_URl, force_rollback=True) metadata = sqlalchemy.MetaData() +class Child(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="children", + ) + + id: int = ormar.Integer(name="child_id", primary_key=True) + first_name: str = ormar.String(name="fname", max_length=100) + last_name: str = ormar.String(name="lname", max_length=100) + born_year: int = ormar.Integer(name="year_born", nullable=True) + + class ArtistChildren(ormar.Model): - class Meta: - tablename = "children_x_artists" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="children_x_artists", + ) class Artist(ormar.Model): - class Meta: - tablename = "artists" - metadata = metadata - database = database + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="artists", + ) id: int = ormar.Integer(name="artist_id", primary_key=True) first_name: str = ormar.String(name="fname", max_length=100) diff --git a/docs_src/models/docs011.py b/docs_src/models/docs011.py deleted file mode 100644 index 7f959240f..000000000 --- a/docs_src/models/docs011.py +++ /dev/null @@ -1,19 +0,0 @@ -import databases -import ormar -import sqlalchemy - -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() - - -class Course(ormar.Model): - class Meta: - database = database - metadata = metadata - - id: ormar.Integer(primary_key=True) - name: ormar.String(max_length=100) - completed: ormar.Boolean(default=False) - - -c1 = Course() diff --git a/docs_src/models/docs012.py b/docs_src/models/docs012.py index ddc0d5b9d..47b87a073 100644 --- a/docs_src/models/docs012.py +++ b/docs_src/models/docs012.py @@ -7,9 +7,10 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id = ormar.Integer(primary_key=True) name = ormar.String(max_length=100) diff --git a/docs_src/models/docs013.py b/docs_src/models/docs013.py index b37927806..fbd85efe3 100644 --- a/docs_src/models/docs013.py +++ b/docs_src/models/docs013.py @@ -4,23 +4,18 @@ import ormar import sqlalchemy -database = databases.Database("sqlite:///test.db", force_rollback=True) -metadata = sqlalchemy.MetaData() +DATABASE_URL = "sqlite:///test.db" - -# note that you do not have to subclass ModelMeta, -# it's useful for type hints and code completion -class MainMeta(ormar.ModelMeta): - metadata = metadata - database = database +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Artist(ormar.Model): - class Meta(MainMeta): - # note that tablename is optional - # if not provided ormar will user class.__name__.lower()+'s' - # -> artists in this example - pass + # note that tablename is optional + # if not provided ormar will user class.__name__.lower()+'s' + # -> artists in this example + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=100) @@ -29,8 +24,7 @@ class Meta(MainMeta): class Album(ormar.Model): - class Meta(MainMeta): - pass + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/models/docs014.py b/docs_src/models/docs014.py index faca1f75c..0429b931c 100644 --- a/docs_src/models/docs014.py +++ b/docs_src/models/docs014.py @@ -7,9 +7,10 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/models/docs015.py b/docs_src/models/docs015.py index 44a524249..a6d67164f 100644 --- a/docs_src/models/docs015.py +++ b/docs_src/models/docs015.py @@ -1,21 +1,21 @@ import databases import ormar import sqlalchemy -from ormar import property_field database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) completed: bool = ormar.Boolean(default=False) - @property_field + @property def prefixed_name(self): return "custom_prefix__" + self.name diff --git a/docs_src/models/docs016.py b/docs_src/models/docs016.py index 21196dde4..e1881d81d 100644 --- a/docs_src/models/docs016.py +++ b/docs_src/models/docs016.py @@ -7,12 +7,12 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) - class Config: - allow_mutation = False + model_config = dict(allow_mutation=False) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/models/docs017.py b/docs_src/models/docs017.py index 155f68c08..4cc9abc58 100644 --- a/docs_src/models/docs017.py +++ b/docs_src/models/docs017.py @@ -7,13 +7,14 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, # define your constraints in Meta class of the model # it's a list that can contain multiple constraints # hera a combination of name and column will have a compound index in the db - constraints = [ormar.IndexColumns("name", "completed")] + constraints=[ormar.IndexColumns("name", "completed")], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/models/docs018.py b/docs_src/models/docs018.py index edc30958c..3fdfe03a2 100644 --- a/docs_src/models/docs018.py +++ b/docs_src/models/docs018.py @@ -9,15 +9,16 @@ class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, # define your constraints in Meta class of the model # it's a list that can contain multiple constraints # hera a combination of name and column will have a level check in the db - constraints = [ + constraints=[ ormar.CheckColumns("start_time < end_time", name="date_check"), - ] + ], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/queries/docs001.py b/docs_src/queries/docs001.py index 850030eb5..94dde1bde 100644 --- a/docs_src/queries/docs001.py +++ b/docs_src/queries/docs001.py @@ -4,25 +4,22 @@ import ormar import sqlalchemy -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Album(ormar.Model): - class Meta: - tablename = "album" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="album") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Track(ormar.Model): - class Meta: - tablename = "track" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="track") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) diff --git a/docs_src/queries/docs002.py b/docs_src/queries/docs002.py index 7d18aa7d5..55117053b 100644 --- a/docs_src/queries/docs002.py +++ b/docs_src/queries/docs002.py @@ -1,16 +1,21 @@ +import asyncio + import databases import ormar import sqlalchemy +from examples import create_drop_database + +DATABASE_URL = "sqlite:///test.db" -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Book(ormar.Model): - class Meta: - tablename = "books" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy( + tablename="books", + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -22,10 +27,21 @@ class Meta: ) -await Book.objects.create(title="Tom Sawyer", author="Twain, Mark", genre="Adventure") -await Book.objects.create(title="War and Peace", author="Tolstoy, Leo", genre="Fiction") -await Book.objects.create(title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction") +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + await Book.objects.create( + title="Tom Sawyer", author="Twain, Mark", genre="Adventure" + ) + await Book.objects.create( + title="War and Peace", author="Tolstoy, Leo", genre="Fiction" + ) + await Book.objects.create( + title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction" + ) + + await Book.objects.update(each=True, genre="Fiction") + all_books = await Book.objects.filter(genre="Fiction").all() + assert len(all_books) == 3 + -await Book.objects.update(each=True, genre="Fiction") -all_books = await Book.objects.filter(genre="Fiction").all() -assert len(all_books) == 3 +asyncio.run(run_query()) diff --git a/docs_src/queries/docs003.py b/docs_src/queries/docs003.py index d8b3b6594..a0f310a71 100644 --- a/docs_src/queries/docs003.py +++ b/docs_src/queries/docs003.py @@ -1,16 +1,19 @@ +import asyncio + import databases import ormar import sqlalchemy +from examples import create_drop_database + +DATABASE_URL = "sqlite:///test.db" -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Book(ormar.Model): - class Meta: - tablename = "books" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -22,16 +25,27 @@ class Meta: ) -await Book.objects.create(title="Tom Sawyer", author="Twain, Mark", genre="Adventure") -await Book.objects.create(title="War and Peace", author="Tolstoy, Leo", genre="Fiction") -await Book.objects.create(title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction") +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + await Book.objects.create( + title="Tom Sawyer", author="Twain, Mark", genre="Adventure" + ) + await Book.objects.create( + title="War and Peace", author="Tolstoy, Leo", genre="Fiction" + ) + await Book.objects.create( + title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction" + ) + + # if not exist the instance will be persisted in db + vol2 = await Book.objects.update_or_create( + title="Volume II", author="Anonymous", genre="Fiction" + ) + assert await Book.objects.count() == 4 + + # if pk or pkname passed in kwargs (like id here) the object will be updated + assert await Book.objects.update_or_create(id=vol2.id, genre="Historic") + assert await Book.objects.count() == 4 -# if not exist the instance will be persisted in db -vol2 = await Book.objects.update_or_create( - title="Volume II", author="Anonymous", genre="Fiction" -) -assert await Book.objects.count() == 1 -# if pk or pkname passed in kwargs (like id here) the object will be updated -assert await Book.objects.update_or_create(id=vol2.id, genre="Historic") -assert await Book.objects.count() == 1 +asyncio.run(run_query()) diff --git a/docs_src/queries/docs004.py b/docs_src/queries/docs004.py index 6aaf01fc6..f23760046 100644 --- a/docs_src/queries/docs004.py +++ b/docs_src/queries/docs004.py @@ -1,30 +1,38 @@ +import asyncio + import databases import ormar import sqlalchemy +from examples import create_drop_database + +DATABASE_URL = "sqlite:///test.db" -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class ToDo(ormar.Model): - class Meta: - tablename = "todos" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="todos") id: int = ormar.Integer(primary_key=True) text: str = ormar.String(max_length=500) completed = ormar.Boolean(default=False) -# create multiple instances at once with bulk_create -await ToDo.objects.bulk_create( - [ - ToDo(text="Buy the groceries."), - ToDo(text="Call Mum.", completed=True), - ToDo(text="Send invoices.", completed=True), - ] -) +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + # create multiple instances at once with bulk_create + await ToDo.objects.bulk_create( + [ + ToDo(text="Buy the groceries."), + ToDo(text="Call Mum.", completed=True), + ToDo(text="Send invoices.", completed=True), + ] + ) + + todoes = await ToDo.objects.all() + assert len(todoes) == 3 + -todoes = await ToDo.objects.all() -assert len(todoes) == 3 +asyncio.run(run_query()) diff --git a/docs_src/queries/docs005.py b/docs_src/queries/docs005.py index 01111236c..3145b9216 100644 --- a/docs_src/queries/docs005.py +++ b/docs_src/queries/docs005.py @@ -1,16 +1,19 @@ +import asyncio + import databases import ormar import sqlalchemy +from examples import create_drop_database + +DATABASE_URL = "sqlite:///test.db" -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Book(ormar.Model): - class Meta: - tablename = "books" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -22,14 +25,23 @@ class Meta: ) -await Book.objects.create(title="Tom Sawyer", author="Twain, Mark", genre="Adventure") -await Book.objects.create( - title="War and Peace in Space", author="Tolstoy, Leo", genre="Fantasy" -) -await Book.objects.create(title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction") +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + await Book.objects.create( + title="Tom Sawyer", author="Twain, Mark", genre="Adventure" + ) + await Book.objects.create( + title="War and Peace in Space", author="Tolstoy, Leo", genre="Fantasy" + ) + await Book.objects.create( + title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction" + ) + + # delete accepts kwargs that will be used in filter + # acting in same way as queryset.filter(**kwargs).delete() + await Book.objects.delete(genre="Fantasy") # delete all fantasy books + all_books = await Book.objects.all() + assert len(all_books) == 2 + -# delete accepts kwargs that will be used in filter -# acting in same way as queryset.filter(**kwargs).delete() -await Book.objects.delete(genre="Fantasy") # delete all fantasy books -all_books = await Book.objects.all() -assert len(all_books) == 2 +asyncio.run(run_query()) diff --git a/docs_src/queries/docs006.py b/docs_src/queries/docs006.py index 2a26b7005..0367f6c74 100644 --- a/docs_src/queries/docs006.py +++ b/docs_src/queries/docs006.py @@ -1,17 +1,19 @@ +import asyncio + import databases import ormar import sqlalchemy -from tests.settings import DATABASE_URL +from examples import create_drop_database + +DATABASE_URL = "sqlite:///test.db" -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -19,10 +21,7 @@ class Meta: class Car(ormar.Model): - class Meta: - tablename = "cars" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="cars") id: int = ormar.Integer(primary_key=True) manufacturer = ormar.ForeignKey(Company) @@ -33,29 +32,34 @@ class Meta: aircon_type: str = ormar.String(max_length=20, nullable=True) -# build some sample data -toyota = await Company.objects.create(name="Toyota", founded=1937) -await Car.objects.create( - manufacturer=toyota, - name="Corolla", - year=2020, - gearbox_type="Manual", - gears=5, - aircon_type="Manual", -) -await Car.objects.create( - manufacturer=toyota, - name="Yaris", - year=2019, - gearbox_type="Manual", - gears=5, - aircon_type="Manual", -) -await Car.objects.create( - manufacturer=toyota, - name="Supreme", - year=2020, - gearbox_type="Auto", - gears=6, - aircon_type="Auto", -) +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + # build some sample data + toyota = await Company.objects.create(name="Toyota", founded=1937) + await Car.objects.create( + manufacturer=toyota, + name="Corolla", + year=2020, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", + ) + await Car.objects.create( + manufacturer=toyota, + name="Yaris", + year=2019, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", + ) + await Car.objects.create( + manufacturer=toyota, + name="Supreme", + year=2020, + gearbox_type="Auto", + gears=6, + aircon_type="Auto", + ) + + +asyncio.run(run_query()) diff --git a/docs_src/queries/docs007.py b/docs_src/queries/docs007.py index 000462cef..6b5189236 100644 --- a/docs_src/queries/docs007.py +++ b/docs_src/queries/docs007.py @@ -1,41 +1,45 @@ +import asyncio + import databases import ormar import sqlalchemy -from tests.settings import DATABASE_URL +from examples import create_drop_database + +DATABASE_URL = "sqlite:///test.db" -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Owner(ormar.Model): - class Meta: - tablename = "owners" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="owners") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Toy(ormar.Model): - class Meta: - tablename = "toys" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="toys") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) owner: Owner = ormar.ForeignKey(Owner) -# build some sample data -aphrodite = await Owner.objects.create(name="Aphrodite") -hermes = await Owner.objects.create(name="Hermes") -zeus = await Owner.objects.create(name="Zeus") +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + # build some sample data + aphrodite = await Owner.objects.create(name="Aphrodite") + hermes = await Owner.objects.create(name="Hermes") + zeus = await Owner.objects.create(name="Zeus") + + await Toy.objects.create(name="Toy 4", owner=zeus) + await Toy.objects.create(name="Toy 5", owner=hermes) + await Toy.objects.create(name="Toy 2", owner=aphrodite) + await Toy.objects.create(name="Toy 1", owner=zeus) + await Toy.objects.create(name="Toy 3", owner=aphrodite) + await Toy.objects.create(name="Toy 6", owner=hermes) + -await Toy.objects.create(name="Toy 4", owner=zeus) -await Toy.objects.create(name="Toy 5", owner=hermes) -await Toy.objects.create(name="Toy 2", owner=aphrodite) -await Toy.objects.create(name="Toy 1", owner=zeus) -await Toy.objects.create(name="Toy 3", owner=aphrodite) -await Toy.objects.create(name="Toy 6", owner=hermes) +asyncio.run(run_query()) diff --git a/docs_src/queries/docs008.py b/docs_src/queries/docs008.py index 8ee2c5921..f60ab6772 100644 --- a/docs_src/queries/docs008.py +++ b/docs_src/queries/docs008.py @@ -1,17 +1,20 @@ +import asyncio + import databases import ormar import sqlalchemy -from tests.settings import DATABASE_URL +from examples import create_drop_database +from pydantic import ValidationError + +DATABASE_URL = "sqlite:///test.db" -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -19,10 +22,7 @@ class Meta: class Car(ormar.Model): - class Meta: - tablename = "cars" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="cars") id: int = ormar.Integer(primary_key=True) manufacturer = ormar.ForeignKey(Company) @@ -33,67 +33,81 @@ class Meta: aircon_type: str = ormar.String(max_length=20, nullable=True) -# build some sample data -toyota = await Company.objects.create(name="Toyota", founded=1937) -await Car.objects.create( - manufacturer=toyota, - name="Corolla", - year=2020, - gearbox_type="Manual", - gears=5, - aircon_type="Manual", -) -await Car.objects.create( - manufacturer=toyota, - name="Yaris", - year=2019, - gearbox_type="Manual", - gears=5, - aircon_type="Manual", -) -await Car.objects.create( - manufacturer=toyota, - name="Supreme", - year=2020, - gearbox_type="Auto", - gears=6, - aircon_type="Auto", -) +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + # build some sample data + toyota = await Company.objects.create(name="Toyota", founded=1937) + await Car.objects.create( + manufacturer=toyota, + name="Corolla", + year=2020, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", + ) + await Car.objects.create( + manufacturer=toyota, + name="Yaris", + year=2019, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", + ) + await Car.objects.create( + manufacturer=toyota, + name="Supreme", + year=2020, + gearbox_type="Auto", + gears=6, + aircon_type="Auto", + ) -# select manufacturer but only name - to include related models use notation {model_name}__{column} -all_cars = ( - await Car.objects.select_related("manufacturer") - .exclude_fields( - ["year", "gearbox_type", "gears", "aircon_type", "company__founded"] + # select manufacturer but only name, + # to include related models use notation {model_name}__{column} + all_cars = ( + await Car.objects.select_related("manufacturer") + .exclude_fields( + ["year", "gearbox_type", "gears", "aircon_type", "manufacturer__founded"] + ) + .all() ) - .all() -) -for car in all_cars: - # excluded columns will yield None - assert all( - getattr(car, x) is None - for x in ["year", "gearbox_type", "gears", "aircon_type"] + for car in all_cars: + # excluded columns will yield None + assert all( + getattr(car, x) is None + for x in ["year", "gearbox_type", "gears", "aircon_type"] + ) + # included column on related models will be available, + # pk column is always included + # even if you do not include it in fields list + assert car.manufacturer.name == "Toyota" + # also in the nested related models - + # you cannot exclude pk - it's always auto added + assert car.manufacturer.founded is None + + # fields() can be called several times, + # building up the columns to select, + # models selected in select_related + # but with no columns in fields list implies all fields + all_cars = ( + await Car.objects.select_related("manufacturer") + .exclude_fields("year") + .exclude_fields(["gear", "gearbox_type"]) + .all() ) - # included column on related models will be available, pk column is always included - # even if you do not include it in fields list - assert car.manufacturer.name == "Toyota" - # also in the nested related models - you cannot exclude pk - it's always auto added - assert car.manufacturer.founded is None - -# fields() can be called several times, building up the columns to select -# models selected in select_related but with no columns in fields list implies all fields -all_cars = ( - await Car.objects.select_related("manufacturer") - .exclude_fields("year") - .exclude_fields(["gear", "gearbox_type"]) - .all() -) -# all fiels from company model are selected -assert all_cars[0].manufacturer.name == "Toyota" -assert all_cars[0].manufacturer.founded == 1937 - -# cannot exclude mandatory model columns - company__name in this example - note usage of dict/set this time -await Car.objects.select_related("manufacturer").exclude_fields( - [{"company": {"name"}}] -).all() -# will raise pydantic ValidationError as company.name is required + # all fiels from company model are selected + assert all_cars[0].manufacturer.name == "Toyota" + assert all_cars[0].manufacturer.founded == 1937 + + # cannot exclude mandatory model columns - + # manufacturer__name in this example - note usage of dict/set this time + try: + await Car.objects.select_related("manufacturer").exclude_fields( + {"manufacturer": {"name"}} + ).all() + except ValidationError: + # will raise pydantic ValidationError as company.name is required + pass + + +asyncio.run(run_query()) diff --git a/docs_src/queries/docs009.py b/docs_src/queries/docs009.py index 5e2bcedac..3a336fc05 100644 --- a/docs_src/queries/docs009.py +++ b/docs_src/queries/docs009.py @@ -1,29 +1,70 @@ -# 1. like in example above -await Car.objects.select_related("manufacturer").fields( - ["id", "name", "manufacturer__name"] -).all() - -# 2. to mark a field as required use ellipsis -await Car.objects.select_related("manufacturer").fields( - {"id": ..., "name": ..., "manufacturer": {"name": ...}} -).all() - -# 3. to include whole nested model use ellipsis -await Car.objects.select_related("manufacturer").fields( - {"id": ..., "name": ..., "manufacturer": ...} -).all() - -# 4. to specify fields at last nesting level you can also use set - equivalent to 2. above -await Car.objects.select_related("manufacturer").fields( - {"id": ..., "name": ..., "manufacturer": {"name"}} -).all() - -# 5. of course set can have multiple fields -await Car.objects.select_related("manufacturer").fields( - {"id": ..., "name": ..., "manufacturer": {"name", "founded"}} -).all() - -# 6. you can include all nested fields but it will be equivalent of 3. above which is shorter -await Car.objects.select_related("manufacturer").fields( - {"id": ..., "name": ..., "manufacturer": {"id", "name", "founded"}} -).all() +import asyncio + +import databases +import ormar +import sqlalchemy +from examples import create_drop_database + +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) + + +class Company(ormar.Model): + ormar_config = ormar_base_config.copy(tablename="companies") + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + founded: int = ormar.Integer(nullable=True) + + +class Car(ormar.Model): + ormar_config = ormar_base_config.copy(tablename="cars") + + id: int = ormar.Integer(primary_key=True) + manufacturer = ormar.ForeignKey(Company) + name: str = ormar.String(max_length=100) + year: int = ormar.Integer(nullable=True) + gearbox_type: str = ormar.String(max_length=20, nullable=True) + gears: int = ormar.Integer(nullable=True) + aircon_type: str = ormar.String(max_length=20, nullable=True) + + +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + # 1. like in example above + await Car.objects.select_related("manufacturer").fields( + ["id", "name", "manufacturer__name"] + ).all() + + # 2. to mark a field as required use ellipsis + await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": {"name": ...}} + ).all() + + # 3. to include whole nested model use ellipsis + await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": ...} + ).all() + + # 4. to specify fields at last nesting level you can also use set + # - equivalent to 2. above + await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": {"name"}} + ).all() + + # 5. of course set can have multiple fields + await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": {"name", "founded"}} + ).all() + + # 6. you can include all nested fields, + # but it will be equivalent of 3. above which is shorter + await Car.objects.select_related("manufacturer").fields( + {"id": ..., "name": ..., "manufacturer": {"id", "name", "founded"}} + ).all() + + +asyncio.run(run_query()) diff --git a/docs_src/relations/docs001.py b/docs_src/relations/docs001.py index 39862469a..ac9e0b1d0 100644 --- a/docs_src/relations/docs001.py +++ b/docs_src/relations/docs001.py @@ -9,18 +9,20 @@ class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/relations/docs002.py b/docs_src/relations/docs002.py index 378f41d7f..b39d66c2d 100644 --- a/docs_src/relations/docs002.py +++ b/docs_src/relations/docs002.py @@ -4,15 +4,15 @@ import ormar import sqlalchemy -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) class Author(ormar.Model): - class Meta: - tablename = "authors" - database = database - metadata = metadata + ormar_config = ormar_base_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -20,20 +20,14 @@ class Meta: class Category(ormar.Model): - class Meta: - tablename = "categories" - database = database - metadata = metadata + ormar_config = ormar_base_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - class Meta: - tablename = "posts" - database = database - metadata = metadata + ormar_config = ormar_base_config.copy(tablename="posts") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) diff --git a/docs_src/relations/docs003.py b/docs_src/relations/docs003.py index fe33608e6..f1d604458 100644 --- a/docs_src/relations/docs003.py +++ b/docs_src/relations/docs003.py @@ -1,16 +1,25 @@ +from typing import Dict, Optional, Union + +import databases +import ormar +import sqlalchemy + +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) + + class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs_src/relations/docs004.py b/docs_src/relations/docs004.py index 8b76059b0..5c9a3b428 100644 --- a/docs_src/relations/docs004.py +++ b/docs_src/relations/docs004.py @@ -1,20 +1,23 @@ -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, +import databases +import ormar +import sqlalchemy + +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() ) class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = ormar_base_config.copy(tablename="categories") id = ormar.Integer(primary_key=True) name = ormar.String(max_length=40) class PostCategory(ormar.Model): - class Meta(BaseMeta): - tablename = "posts_x_categories" + ormar_config = ormar_base_config.copy(tablename="posts_x_categories") id: int = ormar.Integer(primary_key=True) sort_order: int = ormar.Integer(nullable=True) @@ -22,8 +25,7 @@ class Meta(BaseMeta): class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = ormar_base_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) diff --git a/docs_src/signals/docs002.py b/docs_src/signals/docs002.py index 5b1a15f43..fd42ed337 100644 --- a/docs_src/signals/docs002.py +++ b/docs_src/signals/docs002.py @@ -1,5 +1,28 @@ +import asyncio + +import databases +import ormar +import sqlalchemy +from examples import create_drop_database from ormar import pre_update +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) + + +class Album(ormar.Model): + ormar_config = ormar_base_config.copy( + tablename="albums", + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + is_best_seller: bool = ormar.Boolean(default=False) + play_count: int = ormar.Integer(default=0) + @pre_update(Album) async def before_update(sender, instance, **kwargs): @@ -7,16 +30,21 @@ async def before_update(sender, instance, **kwargs): instance.is_best_seller = True -# here album.play_count ans is_best_seller get default values -album = await Album.objects.create(name="Venice") -assert not album.is_best_seller -assert album.play_count == 0 +@create_drop_database(base_config=ormar_base_config) +async def run_query(): + # here album.play_count ans is_best_seller get default values + album = await Album.objects.create(name="Venice") + assert not album.is_best_seller + assert album.play_count == 0 + + album.play_count = 30 + # here a trigger is called but play_count is too low + await album.update() + assert not album.is_best_seller + + album.play_count = 60 + await album.update() + assert album.is_best_seller -album.play_count = 30 -# here a trigger is called but play_count is too low -await album.update() -assert not album.is_best_seller -album.play_count = 60 -await album.update() -assert album.is_best_seller +asyncio.run(run_query()) diff --git a/docs_src/test_all_docs.py b/docs_src/test_all_docs.py new file mode 100644 index 000000000..40ab39333 --- /dev/null +++ b/docs_src/test_all_docs.py @@ -0,0 +1,22 @@ +import os +import subprocess + +import pytest + +filepaths = [] +root_dir = os.getcwd() +for dirpath, dirnames, filenames in os.walk(root_dir): + for filename in filenames: + if ( + filename.endswith(".py") + and not filename.endswith("__init__.py") + and os.path.join(root_dir, filename) != __file__ + ): + filepath_ = os.path.join(dirpath, filename) + filepaths.append(filepath_) + + +@pytest.mark.parametrize("filepath", filepaths) +def test_all_docs(filepath: str): + result = subprocess.run(["poetry", "run", "python", filepath]) + assert result.returncode == 0 diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 000000000..b574bee0b --- /dev/null +++ b/examples/__init__.py @@ -0,0 +1,3 @@ +from .utils import create_drop_database + +__all__ = ["create_drop_database"] diff --git a/examples/fastapi_quick_start.py b/examples/fastapi_quick_start.py index 61d1c1e6e..e2d2eb11b 100644 --- a/examples/fastapi_quick_start.py +++ b/examples/fastapi_quick_start.py @@ -6,6 +6,13 @@ import uvicorn from fastapi import FastAPI +DATABASE_URL = "sqlite:///test.db" + +ormar_base_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() +) + + app = FastAPI() metadata = sqlalchemy.MetaData() database = databases.Database("sqlite:///test.db") @@ -27,20 +34,14 @@ async def shutdown() -> None: class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = ormar_base_config.copy(tablename="items") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/examples/script_from_readme.py b/examples/script_from_readme.py index 72acdd9c1..841bbd3d3 100644 --- a/examples/script_from_readme.py +++ b/examples/script_from_readme.py @@ -21,24 +21,22 @@ # Note that all type hints are optional # below is a perfectly valid model declaration # class Author(ormar.Model): -# class Meta(BaseMeta): -# tablename = "authors" +# ormar_config = base_ormar_config.copy(tablename="authors") # # id = ormar.Integer(primary_key=True) # <= notice no field types # name = ormar.String(max_length=100) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) diff --git a/examples/utils.py b/examples/utils.py new file mode 100644 index 000000000..f2f9b6ba0 --- /dev/null +++ b/examples/utils.py @@ -0,0 +1,21 @@ +import functools + +import ormar +import sqlalchemy + + +def create_drop_database(base_config: ormar.OrmarConfig) -> None: + # create all tables in the database before execution + # and drop them after, note that in production you should use migrations + def wrapper(func): + @functools.wraps(func) + async def wrapped(*args): + engine = sqlalchemy.create_engine(str(base_config.database.url)) + base_config.metadata.drop_all(engine) + base_config.metadata.create_all(engine) + await func(*args) + base_config.metadata.drop_all(engine) + + return wrapped + + return wrapper diff --git a/ormar/__init__.py b/ormar/__init__.py index b25cc4ee9..ef1a8fae2 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -19,11 +19,12 @@ And what's a better name for python ORM than snakes cabinet :) """ + try: from importlib.metadata import version # type: ignore except ImportError: # pragma: no cover from importlib_metadata import version # type: ignore -from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I100 +from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I001 from ormar.decorators import ( # noqa: I100 post_bulk_update, post_delete, diff --git a/ormar/decorators/__init__.py b/ormar/decorators/__init__.py index 1d71d6cda..04005f26c 100644 --- a/ormar/decorators/__init__.py +++ b/ormar/decorators/__init__.py @@ -6,6 +6,7 @@ * predefined signals decorators (pre/post + save/update/delete) """ + from ormar.decorators.signals import ( post_bulk_update, post_delete, diff --git a/ormar/fields/__init__.py b/ormar/fields/__init__.py index a9dcd7f2d..84d2acbd5 100644 --- a/ormar/fields/__init__.py +++ b/ormar/fields/__init__.py @@ -4,6 +4,7 @@ as well as relation Fields (ForeignKey, ManyToMany). Also a definition for custom CHAR based sqlalchemy UUID field """ + from ormar.fields.base import BaseField from ormar.fields.constraints import CheckColumns, IndexColumns, UniqueColumns from ormar.fields.foreign_key import ForeignKey, ForeignKeyField diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index f9c75e9b1..8c59496e9 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -362,12 +362,14 @@ def default_source_field_name(self) -> str: prefix = "to_" if self.self_reference else "" return self.through_relation_name or f"{prefix}{self.owner.get_name()}" - def _evaluate_forward_ref(self, globalns: Any, localns: Any, is_through: bool = False) -> None: + def _evaluate_forward_ref( + self, globalns: Any, localns: Any, is_through: bool = False + ) -> None: target = "through" if is_through else "to" target_obj = getattr(self, target) if sys.version_info.minor <= 8: # pragma: no cover evaluated = target_obj._evaluate(globalns, localns) - else: # pragma: no cover + else: # pragma: no cover evaluated = target_obj._evaluate(globalns, localns, set()) setattr(self, target, evaluated) diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index d44876453..499c25f6d 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -64,7 +64,9 @@ def populate_m2m_params_based_on_to_model( """ to_field = to.ormar_config.model_fields[to.ormar_config.pkname] pk_only_model = create_dummy_model(to, to_field) - base_type = Union[to_field.__type__, to, pk_only_model, List[to], List[pk_only_model]] # type: ignore + base_type = Union[ + to_field.__type__, to, pk_only_model, List[to], List[pk_only_model] + ] # type: ignore __type__ = ( base_type # type: ignore if not nullable diff --git a/ormar/fields/model_fields.py b/ormar/fields/model_fields.py index f7405b8e7..c81faf870 100644 --- a/ormar/fields/model_fields.py +++ b/ormar/fields/model_fields.py @@ -104,9 +104,11 @@ def __new__(cls, *args: Any, **kwargs: Any) -> BaseField: # type: ignore namespace = dict( __type__=field_type, - __pydantic_type__=overwrite_pydantic_type - if overwrite_pydantic_type is not None - else field_type, + __pydantic_type__=( + overwrite_pydantic_type + if overwrite_pydantic_type is not None + else field_type + ), __sample__=cls._sample, alias=kwargs.pop("name", None), name=None, @@ -114,6 +116,7 @@ def __new__(cls, *args: Any, **kwargs: Any) -> BaseField: # type: ignore default=default, server_default=server_default, nullable=nullable, + annotation=field_type, sql_nullable=sql_nullable, index=kwargs.pop("index", False), unique=kwargs.pop("unique", False), @@ -476,20 +479,17 @@ def get_column_type(cls, **kwargs: Any) -> Any: @overload def LargeBinary( # type: ignore max_length: int, *, represent_as_base64_str: Literal[True], **kwargs: Any - ) -> str: - ... + ) -> str: ... @overload def LargeBinary( # type: ignore max_length: int, *, represent_as_base64_str: Literal[False], **kwargs: Any - ) -> bytes: - ... + ) -> bytes: ... @overload def LargeBinary( max_length: int, represent_as_base64_str: Literal[False] = ..., **kwargs: Any - ) -> bytes: - ... + ) -> bytes: ... def LargeBinary( max_length: int, represent_as_base64_str: bool = False, **kwargs: Any diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index f62d2ac97..7b031ced9 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -23,15 +23,15 @@ def encode_bool(value: bool) -> str: def encode_decimal(value: decimal.Decimal, precision: int = None) -> float: return ( - round(float(value), precision) - if isinstance(value, decimal.Decimal) - else value + round(float(value), precision) if isinstance(value, decimal.Decimal) else value ) def encode_bytes(value: Union[str, bytes], represent_as_string: bool = False) -> str: if represent_as_string: - value = value if isinstance(value, str) else base64.b64encode(value).decode("utf-8") + value = ( + value if isinstance(value, str) else base64.b64encode(value).decode("utf-8") + ) else: value = value if isinstance(value, str) else value.decode("utf-8") return value @@ -82,7 +82,7 @@ def re_dump_value(value: str) -> Union[str, bytes]: ADDITIONAL_PARAMETERS_MAP: Dict[type, str] = { bytes: "represent_as_base64_str", - decimal.Decimal: "decimal_places" + decimal.Decimal: "decimal_places", } @@ -92,6 +92,8 @@ def re_dump_value(value: str) -> Union[str, bytes]: datetime.date: SchemaValidator(core_schema.date_schema()).validate_python, datetime.time: SchemaValidator(core_schema.time_schema()).validate_python, pydantic.Json: json.loads, - decimal.Decimal: lambda x, precision: decimal.Decimal(x, context=decimal.Context(prec=precision)), + decimal.Decimal: lambda x, precision: decimal.Decimal( + x, context=decimal.Context(prec=precision) + ), bytes: decode_bytes, } diff --git a/ormar/fields/referential_actions.py b/ormar/fields/referential_actions.py index cde15ad05..06e5cf551 100644 --- a/ormar/fields/referential_actions.py +++ b/ormar/fields/referential_actions.py @@ -2,7 +2,6 @@ Gathers all referential actions by ormar. """ - from enum import Enum diff --git a/ormar/fields/sqlalchemy_encrypted.py b/ormar/fields/sqlalchemy_encrypted.py index d17e6d761..6ff894d14 100644 --- a/ormar/fields/sqlalchemy_encrypted.py +++ b/ormar/fields/sqlalchemy_encrypted.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union import sqlalchemy.types as types -from pydantic.utils import lenient_issubclass from sqlalchemy.engine import Dialect import ormar # noqa: I100, I202 @@ -130,7 +129,11 @@ def __init__( "In order to encrypt a column 'cryptography' is required!" ) backend = BACKENDS_MAP.get(encrypt_backend, encrypt_custom_backend) - if not backend or not lenient_issubclass(backend, EncryptBackend): + if ( + not backend + or not isinstance(backend, type) + or not issubclass(backend, EncryptBackend) + ): raise ModelDefinitionError("Wrong or no encrypt backend provided!") self.backend: EncryptBackend = backend() @@ -164,7 +167,9 @@ def process_bind_param(self, value: Any, dialect: Dialect) -> Optional[str]: encoder = ormar.SQL_ENCODERS_MAP.get(self.type_, None) if encoder: if self.type_ in ADDITIONAL_PARAMETERS_MAP: - additional_parameter = getattr(self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_]) + additional_parameter = getattr( + self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_] + ) value = encoder(value, additional_parameter) else: value = encoder(value) # type: ignore @@ -183,7 +188,9 @@ def process_result_value(self, value: Any, dialect: Dialect) -> Any: decoder = ormar.DECODERS_MAP.get(self.type_, None) if decoder: if self.type_ in ADDITIONAL_PARAMETERS_MAP: - additional_parameter = getattr(self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_]) + additional_parameter = getattr( + self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_] + ) return decoder(decrypted_value, additional_parameter) return decoder(decrypted_value) # type: ignore diff --git a/ormar/models/descriptors/descriptors.py b/ormar/models/descriptors/descriptors.py index 92866a898..33e6a69da 100644 --- a/ormar/models/descriptors/descriptors.py +++ b/ormar/models/descriptors/descriptors.py @@ -65,7 +65,9 @@ def __get__(self, instance: "Model", owner: Type["Model"]) -> Any: def __set__(self, instance: "Model", value: Any) -> None: field = instance.ormar_config.model_fields[self.name] if isinstance(value, str): - value = decode_bytes(value=value, represent_as_string=field.represent_as_base64_str) + value = decode_bytes( + value=value, represent_as_string=field.represent_as_base64_str + ) instance._internal_set(self.name, value) instance.set_save_status(False) diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index c8eb01373..e681076b2 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -4,7 +4,6 @@ import pydantic from pydantic import ConfigDict from pydantic.fields import FieldInfo -from pydantic.utils import lenient_issubclass from ormar.exceptions import ModelDefinitionError # noqa: I100, I202 from ormar.fields import BaseField @@ -33,10 +32,6 @@ def create_pydantic_field( model_field.through.model_fields[field_name] = FieldInfo.from_annotated_attribute( annotation=Optional[model], default=None ) - # model.model_fields[model_field.through.get_name()] = FieldInfo.from_annotated_attribute( - # annotation=Optional[model_field.through], default=None - # ) - # model.model_rebuild(force=True) model_field.through.model_rebuild(force=True) @@ -123,7 +118,10 @@ def get_potential_fields(attrs: Union[Dict, MappingProxyType]) -> Dict: return { k: v for k, v in attrs.items() - if (lenient_issubclass(v, BaseField) or isinstance(v, BaseField)) + if ( + (isinstance(v, type) and issubclass(v, BaseField)) + or isinstance(v, BaseField) + ) } diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index e43c57d68..a4f9aefe0 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -107,9 +107,9 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: :type model_field: relation Field """ related_name = model_field.get_related_name() - # TODO: Reverse relations does not register pydantic fields? + related_model_fields = model_field.to.ormar_config.model_fields if model_field.is_multi: - model_field.to.ormar_config.model_fields[related_name] = ManyToMany( # type: ignore + related_model_fields[related_name] = ManyToMany( # type: ignore model_field.owner, through=model_field.through, name=related_name, @@ -128,7 +128,7 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: register_through_shortcut_fields(model_field=model_field) adjust_through_many_to_many_model(model_field=model_field) else: - model_field.to.ormar_config.model_fields[related_name] = ForeignKey( # type: ignore + related_model_fields[related_name] = ForeignKey( # type: ignore model_field.owner, real_name=related_name, virtual=True, @@ -139,7 +139,7 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: skip_field=model_field.skip_reverse, ) if not model_field.skip_reverse: - field_type = model_field.to.ormar_config.model_fields[related_name].__type__ + field_type = related_model_fields[related_name].__type__ field_type = replace_models_with_copy( annotation=field_type, source_model_field=model_field.name ) @@ -162,7 +162,8 @@ def serialize( self, children: List["BaseModel"], handler: SerializerFunctionWrapHandler ) -> Any: """ - Serialize a list of nodes, handling circular references by excluding the children. + Serialize a list of nodes, handling circular references + by excluding the children. """ try: return handler(children) @@ -195,9 +196,7 @@ def replace_models_with_copy( :rtype: Type """ if inspect.isclass(annotation) and issubclass(annotation, ormar.Model): - return create_copy_to_avoid_circular_references( - model=annotation, source_model_field=source_model_field - ) + return create_copy_to_avoid_circular_references(model=annotation) elif hasattr(annotation, "__origin__") and annotation.__origin__ in {list, Union}: if annotation.__origin__ == list: return List[ @@ -219,19 +218,11 @@ def replace_models_with_copy( return annotation -def create_copy_to_avoid_circular_references( - model: Type["Model"], source_model_field: Optional[str] = None -) -> Type["BaseModel"]: - # original_field = model.model_fields.pop(source_model_field, None) - # original_annotation = model.__dict__.get("__annotations__", {}).pop(source_model_field, None) - # original_ormar_field = model.ormar_config.model_fields.pop(source_model_field, None) +def create_copy_to_avoid_circular_references(model: Type["Model"]) -> Type["BaseModel"]: new_model = create_model( model.__name__, __base__=model, ) - # model.model_fields[source_model_field] = original_field - # model.__dict__.get("__annotations__", {})[source_model_field] = original_annotation - # model.ormar_config.model_fields[source_model_field] = original_ormar_field return new_model diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 493805997..bb123baa2 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -11,8 +11,6 @@ Union, ) -from pydantic import typing - try: import orjson as json except ImportError: # pragma: no cover @@ -213,6 +211,6 @@ def modify_schema_example(model: Type["Model"]) -> None: # noqa CCR001 :type model: Model class """ if not config_field_not_set(model=model, field_name="model_fields"): - model.model_config[ - "json_schema_extra" - ] = construct_schema_function_without_choices() + model.model_config["json_schema_extra"] = ( + construct_schema_function_without_choices() + ) diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 14c12c61d..dbb0f3f83 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -1,4 +1,5 @@ import copy +import sys from typing import ( TYPE_CHECKING, Any, @@ -695,9 +696,9 @@ def __new__( # type: ignore # noqa: CCR001 and new_model.ormar_config.pkname not in new_model.model_fields ): field_name = new_model.ormar_config.pkname - new_model.model_fields[ - field_name - ] = FieldInfo.from_annotated_attribute(Optional[int], None) + new_model.model_fields[field_name] = ( + FieldInfo.from_annotated_attribute(Optional[int], None) + ) new_model.model_rebuild(force=True) for item in new_model.ormar_config.property_fields: @@ -733,6 +734,13 @@ def __getattr__(self, item: str) -> Any: :return: FieldAccessor for given field :rtype: FieldAccessor """ + # Ugly workaround for name shadowing warnings in pydantic + frame = sys._getframe(1) + if ( + frame.f_code.co_name == "collect_model_fields" + and frame.f_code.co_filename.endswith("pydantic\_internal\_fields.py") + ): + raise AttributeError() if item == "pk": item = self.ormar_config.pkname if item in object.__getattribute__(self, "ormar_config").model_fields: diff --git a/ormar/models/mixins/__init__.py b/ormar/models/mixins/__init__.py index e605ee893..edb5852ca 100644 --- a/ormar/models/mixins/__init__.py +++ b/ormar/models/mixins/__init__.py @@ -4,6 +4,7 @@ The split into mixins was done to ease the maintainability of the proxy class, as it became quite complicated over time. """ + from ormar.models.mixins.alias_mixin import AliasMixin from ormar.models.mixins.excludable_mixin import ExcludableMixin from ormar.models.mixins.merge_mixin import MergeModelMixin diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 2596c5c24..2ce0a535c 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -319,9 +319,13 @@ def _process_kwargs(self, kwargs: Dict) -> Tuple[Dict, Dict]: # noqa: CCR001 k, self._convert_json( k, - model_fields[k].expand_relationship(v, self, to_register=False) - if k in model_fields - else (v if k in pydantic_fields else model_fields[k]), + ( + model_fields[k].expand_relationship( + v, self, to_register=False + ) + if k in model_fields + else (v if k in pydantic_fields else model_fields[k]) + ), ), ) for k, v in kwargs.items() @@ -974,7 +978,9 @@ def _convert_to_bytes(self, column_name: str, value: Any) -> Union[str, Dict]: return value field = self.ormar_config.model_fields[column_name] if value is not None: - value = decode_bytes(value=value, represent_as_string=field.represent_as_base64_str) + value = decode_bytes( + value=value, represent_as_string=field.represent_as_base64_str + ) return value def _convert_bytes_to_str(self, column_name: str, value: Any) -> Union[str, Dict]: diff --git a/ormar/models/quick_access_views.py b/ormar/models/quick_access_views.py index 464d9b1ec..28f19fea1 100644 --- a/ormar/models/quick_access_views.py +++ b/ormar/models/quick_access_views.py @@ -2,6 +2,7 @@ Contains set of fields/methods etc names that are used to bypass the checks in NewBaseModel __getattribute__ calls to speed the calls. """ + quick_access_set = { "Config", "model_config", diff --git a/ormar/protocols/queryset_protocol.py b/ormar/protocols/queryset_protocol.py index 4b7d78150..fb8bcb9dd 100644 --- a/ormar/protocols/queryset_protocol.py +++ b/ormar/protocols/queryset_protocol.py @@ -17,59 +17,44 @@ def filter(self, **kwargs: Any) -> "QuerysetProxy": # noqa: A003, A001 def exclude(self, **kwargs: Any) -> "QuerysetProxy": # noqa: A003, A001 ... - def select_related(self, related: Union[List, str]) -> "QuerysetProxy": - ... + def select_related(self, related: Union[List, str]) -> "QuerysetProxy": ... - def prefetch_related(self, related: Union[List, str]) -> "QuerysetProxy": - ... + def prefetch_related(self, related: Union[List, str]) -> "QuerysetProxy": ... - async def exists(self) -> bool: - ... + async def exists(self) -> bool: ... - async def count(self, distinct: bool = True) -> int: - ... + async def count(self, distinct: bool = True) -> int: ... - async def clear(self) -> int: - ... + async def clear(self) -> int: ... - def limit(self, limit_count: int) -> "QuerysetProxy": - ... + def limit(self, limit_count: int) -> "QuerysetProxy": ... - def offset(self, offset: int) -> "QuerysetProxy": - ... + def offset(self, offset: int) -> "QuerysetProxy": ... - async def first(self, **kwargs: Any) -> "Model": - ... + async def first(self, **kwargs: Any) -> "Model": ... - async def get(self, **kwargs: Any) -> "Model": - ... + async def get(self, **kwargs: Any) -> "Model": ... async def all( # noqa: A003, A001 self, **kwargs: Any - ) -> Sequence[Optional["Model"]]: - ... + ) -> Sequence[Optional["Model"]]: ... - async def create(self, **kwargs: Any) -> "Model": - ... + async def create(self, **kwargs: Any) -> "Model": ... - async def update(self, each: bool = False, **kwargs: Any) -> int: - ... + async def update(self, each: bool = False, **kwargs: Any) -> int: ... async def get_or_create( self, _defaults: Optional[Dict[str, Any]] = None, **kwargs: Any, - ) -> Tuple["Model", bool]: - ... + ) -> Tuple["Model", bool]: ... - async def update_or_create(self, **kwargs: Any) -> "Model": - ... + async def update_or_create(self, **kwargs: Any) -> "Model": ... - def fields(self, columns: Union[List, str, Set, Dict]) -> "QuerysetProxy": - ... + def fields(self, columns: Union[List, str, Set, Dict]) -> "QuerysetProxy": ... - def exclude_fields(self, columns: Union[List, str, Set, Dict]) -> "QuerysetProxy": - ... + def exclude_fields( + self, columns: Union[List, str, Set, Dict] + ) -> "QuerysetProxy": ... - def order_by(self, columns: Union[List, str]) -> "QuerysetProxy": - ... + def order_by(self, columns: Union[List, str]) -> "QuerysetProxy": ... diff --git a/ormar/protocols/relation_protocol.py b/ormar/protocols/relation_protocol.py index b551b8d33..4c44bca5f 100644 --- a/ormar/protocols/relation_protocol.py +++ b/ormar/protocols/relation_protocol.py @@ -10,8 +10,6 @@ class RelationProtocol(Protocol): # pragma: nocover - def add(self, child: "Model") -> None: - ... + def add(self, child: "Model") -> None: ... - def remove(self, child: Union["Model", Type["Model"]]) -> None: - ... + def remove(self, child: Union["Model", Type["Model"]]) -> None: ... diff --git a/ormar/queryset/__init__.py b/ormar/queryset/__init__.py index 7f580747b..02e4eeca2 100644 --- a/ormar/queryset/__init__.py +++ b/ormar/queryset/__init__.py @@ -1,6 +1,7 @@ """ Contains QuerySet and different Query classes to allow for constructing of sql queries. """ + from ormar.queryset.actions import FilterAction, OrderAction, SelectAction from ormar.queryset.clause import and_, or_ from ormar.queryset.field_accessor import FieldAccessor diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index 809b22855..92bfd1d62 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -575,9 +575,11 @@ def order_by(self, columns: Union[List, str, OrderAction]) -> "QuerySet[T]": columns = [columns] orders_by = [ - OrderAction(order_str=x, model_cls=self.model_cls) # type: ignore - if not isinstance(x, OrderAction) - else x + ( + OrderAction(order_str=x, model_cls=self.model_cls) # type: ignore + if not isinstance(x, OrderAction) + else x + ) for x in columns ] diff --git a/ormar/relations/__init__.py b/ormar/relations/__init__.py index 4e4529bdb..15cc9483f 100644 --- a/ormar/relations/__init__.py +++ b/ormar/relations/__init__.py @@ -2,6 +2,7 @@ Package handles relations on models, returning related models on calls and exposing QuerySetProxy for m2m and reverse relations. """ + from ormar.relations.alias_manager import AliasManager from ormar.relations.relation import Relation, RelationType from ormar.relations.relation_manager import RelationsManager diff --git a/ormar/signals/__init__.py b/ormar/signals/__init__.py index 127fc2f1c..86da0ba9a 100644 --- a/ormar/signals/__init__.py +++ b/ormar/signals/__init__.py @@ -2,6 +2,7 @@ Signals and SignalEmitter that gathers the signals on models Meta. Used to signal receivers functions about events, i.e. post_save, pre_delete etc. """ + from ormar.signals.signal import Signal, SignalEmitter __all__ = ["Signal", "SignalEmitter"] diff --git a/poetry.lock b/poetry.lock index 94586c76a..c8a16f377 100644 --- a/poetry.lock +++ b/poetry.lock @@ -172,34 +172,34 @@ test = ["flake8 (>=5.0.4,<5.1.0)", "uvloop (>=0.15.3)"] [[package]] name = "black" -version = "23.12.1" +version = "24.1.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, - {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, - {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, - {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, - {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, - {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, - {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, - {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, - {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, - {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, - {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, - {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, - {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, - {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, - {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, - {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, - {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, - {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, - {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, - {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, - {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, - {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, + {file = "black-24.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94d5280d020dadfafc75d7cae899609ed38653d3f5e82e7ce58f75e76387ed3d"}, + {file = "black-24.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aaf9aa85aaaa466bf969e7dd259547f4481b712fe7ee14befeecc152c403ee05"}, + {file = "black-24.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec489cae76eac3f7573629955573c3a0e913641cafb9e3bfc87d8ce155ebdb29"}, + {file = "black-24.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5a0100b4bdb3744dd68412c3789f472d822dc058bb3857743342f8d7f93a5a7"}, + {file = "black-24.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6cc5a6ba3e671cfea95a40030b16a98ee7dc2e22b6427a6f3389567ecf1b5262"}, + {file = "black-24.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0e367759062dcabcd9a426d12450c6d61faf1704a352a49055a04c9f9ce8f5a"}, + {file = "black-24.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be305563ff4a2dea813f699daaffac60b977935f3264f66922b1936a5e492ee4"}, + {file = "black-24.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a8977774929b5db90442729f131221e58cc5d8208023c6af9110f26f75b6b20"}, + {file = "black-24.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d74d4d0da276fbe3b95aa1f404182562c28a04402e4ece60cf373d0b902f33a0"}, + {file = "black-24.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39addf23f7070dbc0b5518cdb2018468ac249d7412a669b50ccca18427dba1f3"}, + {file = "black-24.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:827a7c0da520dd2f8e6d7d3595f4591aa62ccccce95b16c0e94bb4066374c4c2"}, + {file = "black-24.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:0cd59d01bf3306ff7e3076dd7f4435fcd2fafe5506a6111cae1138fc7de52382"}, + {file = "black-24.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf8dd261ee82df1abfb591f97e174345ab7375a55019cc93ad38993b9ff5c6ad"}, + {file = "black-24.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:82d9452aeabd51d1c8f0d52d4d18e82b9f010ecb30fd55867b5ff95904f427ff"}, + {file = "black-24.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9aede09f72b2a466e673ee9fca96e4bccc36f463cac28a35ce741f0fd13aea8b"}, + {file = "black-24.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:780f13d03066a7daf1707ec723fdb36bd698ffa29d95a2e7ef33a8dd8fe43b5c"}, + {file = "black-24.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a15670c650668399c4b5eae32e222728185961d6ef6b568f62c1681d57b381ba"}, + {file = "black-24.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1e0fa70b8464055069864a4733901b31cbdbe1273f63a24d2fa9d726723d45ac"}, + {file = "black-24.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fa8d9aaa22d846f8c0f7f07391148e5e346562e9b215794f9101a8339d8b6d8"}, + {file = "black-24.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:f0dfbfbacfbf9cd1fac7a5ddd3e72510ffa93e841a69fcf4a6358feab1685382"}, + {file = "black-24.1.0-py3-none-any.whl", hash = "sha256:5134a6f6b683aa0a5592e3fd61dd3519d8acd953d93e2b8b76f9981245b65594"}, + {file = "black-24.1.0.tar.gz", hash = "sha256:30fbf768cd4f4576598b1db0202413fafea9a227ef808d1a12230c643cefe9fc"}, ] [package.dependencies] @@ -2475,4 +2475,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "93d791c31977d250ff40bed40a7b9e48656d1543e0c06188c27ae782a1b3fb27" +content-hash = "90ceff224348336d1d521751ba9a001d77fd31bbaedd0750733365e428ae32ad" diff --git a/pyproject.toml b/pyproject.toml index af367e112..0b63a7cbf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -134,6 +134,7 @@ all = [ [tool.poetry.group.dev.dependencies] httpx = "^0.24.1" asgi-lifespan = "^2.1.0" +black = "^24.1.0" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/scripts/test_docs.sh b/scripts/test_docs.sh new file mode 100644 index 000000000..be49f6d90 --- /dev/null +++ b/scripts/test_docs.sh @@ -0,0 +1,12 @@ +#!/bin/sh -e + +PACKAGE="docs_src" + +PREFIX="" +if [ -d 'venv' ] ; then + PREFIX="venv/bin/" +fi + +set -x + +PYTHONPATH=. ${PREFIX}pytest --ignore venv --cov=${PACKAGE} --cov=tests --cov-report=xml --cov-fail-under=100 --cov-report=term-missing tests/ "${@}" diff --git a/tests/test_deferred/test_same_table_joins.py b/tests/test_deferred/test_same_table_joins.py index c6efc9302..8372c5bf5 100644 --- a/tests/test_deferred/test_same_table_joins.py +++ b/tests/test_deferred/test_same_table_joins.py @@ -106,7 +106,8 @@ async def test_model_multiple_instances_of_same_table_in_schema(): assert len(classes[0].dict().get("students")) == 2 - # since it's going from schoolclass => teacher => schoolclass (same class) department is already populated + # since it's going from schoolclass => teacher + # => schoolclass (same class) department is already populated assert classes[0].students[0].schoolclass.name == "Math" assert classes[0].students[0].schoolclass.department.name is None await classes[0].students[0].schoolclass.department.load() diff --git a/tests/test_encryption/test_encrypted_columns.py b/tests/test_encryption/test_encrypted_columns.py index 7d9745d0b..65f341ec9 100644 --- a/tests/test_encryption/test_encrypted_columns.py +++ b/tests/test_encryption/test_encrypted_columns.py @@ -70,7 +70,9 @@ class Author(ormar.Model): test_decimal = ormar.Decimal(scale=2, precision=10, **default_fernet) test_decimal2 = ormar.Decimal(max_digits=10, decimal_places=2, **default_fernet) test_bytes = ormar.LargeBinary(max_length=100, **default_fernet) - test_b64bytes = ormar.LargeBinary(max_length=100, represent_as_base64_str=True, **default_fernet) + test_b64bytes = ormar.LargeBinary( + max_length=100, represent_as_base64_str=True, **default_fernet + ) custom_backend: str = ormar.String( max_length=200, encrypt_secret="asda8", @@ -190,7 +192,7 @@ async def test_save_and_retrieve(): test_json=dict(aa=12), custom_backend="test12", test_bytes=b"test", - test_b64bytes=b"test2" + test_b64bytes=b"test2", ).save() author = await Author.objects.get() diff --git a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py index f5b7244bf..f93766225 100644 --- a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py +++ b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py @@ -325,26 +325,25 @@ async def test_very_complex_relation_map(): { "id": 9, "title": "prueba-2321", - "description": "\n\n### [v.1.3.0.0] - 2021-08-19\n" - "#### Resolved Issues\n\n" - "#### Task\n\n- Probar flujo de changelog Automatic Jira: " - "[SAN-86](https://htech.atlassian.net/browse/SAN-86)\n\n " - "Description: Se probara el flujo de changelog automatic. \n\n " - "Changelog: Se agrega función para extraer texto del campo changelog del " - "dashboard de Sanval y ponerlo directamente en el changelog.md del repositorio." - " \n\n\n \n\n", + "description": "\n" + "Description 1" + "\n", "data": {}, }, { "id": 8, "title": "prueba-123-prod", - "description": "\n\n### [v.1.2.0.0] - 2021-08-19\n#### Resolved Issues\n\n#### Task\n\n- Probar flujo de changelog Automatic Jira: [SAN-86](https://htech.atlassian.net/browse/SAN-86)\n\n Description: Se probara el flujo de changelog automatic. \n\n Changelog: Se agrega función para extraer texto del campo changelog del dashboard de Sanval y ponerlo directamente en el changelog.md del repositorio. \n\n\n \n\n", + "description": "\n" + "Description 2" + "\n", "data": {}, }, { "id": 6, "title": "prueba-3-2", - "description": "\n\n### [v.1.1.0.0] - 2021-07-29\n#### Resolved Issues\n\n#### Task\n\n- Probar flujo de changelog Automatic Jira: [SAN-86](https://htech.atlassian.net/browse/SAN-86)\n\n Description: Se probara el flujo de changelog automatic. \n\n Changelog: Se agrega función para extraer texto del campo changelog del dashboard de Sanval y ponerlo directamente en el changelog.md del repositorio. \n\n\n \n\n", + "description": "\n" + "Description 3" + "\n", "data": {}, }, ] @@ -362,7 +361,9 @@ async def test_very_complex_relation_map(): { "id": 9, "title": "prueba-2321", - "description": "\n\n### [v.1.3.0.0] - 2021-08-19\n#### Resolved Issues\n\n#### Task\n\n- Probar flujo de changelog Automatic Jira: [SAN-86](https://htech.atlassian.net/browse/SAN-86)\n\n Description: Se probara el flujo de changelog automatic. \n\n Changelog: Se agrega función para extraer texto del campo changelog del dashboard de Sanval y ponerlo directamente en el changelog.md del repositorio. \n\n\n \n\n", + "description": "\n" + "Description 1" + "\n", "data": {}, "tag": { "id": 18, @@ -372,7 +373,9 @@ async def test_very_complex_relation_map(): { "id": 8, "title": "prueba-123-prod", - "description": "\n\n### [v.1.2.0.0] - 2021-08-19\n#### Resolved Issues\n\n#### Task\n\n- Probar flujo de changelog Automatic Jira: [SAN-86](https://htech.atlassian.net/browse/SAN-86)\n\n Description: Se probara el flujo de changelog automatic. \n\n Changelog: Se agrega función para extraer texto del campo changelog del dashboard de Sanval y ponerlo directamente en el changelog.md del repositorio. \n\n\n \n\n", + "description": "\n" + "Description 2" + "\n", "data": {}, "tag": { "id": 17, @@ -382,7 +385,9 @@ async def test_very_complex_relation_map(): { "id": 6, "title": "prueba-3-2", - "description": "\n\n### [v.1.1.0.0] - 2021-07-29\n#### Resolved Issues\n\n#### Task\n\n- Probar flujo de changelog Automatic Jira: [SAN-86](https://htech.atlassian.net/browse/SAN-86)\n\n Description: Se probara el flujo de changelog automatic. \n\n Changelog: Se agrega función para extraer texto del campo changelog del dashboard de Sanval y ponerlo directamente en el changelog.md del repositorio. \n\n\n \n\n", + "description": "\n" + "Description 3" + "\n", "data": {}, "tag": { "id": 12, diff --git a/tests/test_exclude_include_dict/test_excluding_nested_models_lists.py b/tests/test_exclude_include_dict/test_excluding_nested_models_lists.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index 14343aedb..9eb6c2c91 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -203,20 +203,34 @@ async def test_excluding_nested_lists_in_dump(): gears=5, aircon_type="Manual", ) - manufacturer = await Company.objects.select_related("cars").get(name="Toyota") - assert manufacturer.dict() == {'cars': [{'aircon_type': 'Manual', - 'gearbox_type': 'Manual', - 'gears': 5, - 'id': car1.id, - 'name': 'Corolla', - 'year': 2020}, - {'aircon_type': 'Manual', - 'gearbox_type': 'Manual', - 'gears': 5, - 'id': car2.id, - 'name': 'Yaris', - 'year': 2019}], - 'founded': 1937, - 'id': toyota.id, - 'name': 'Toyota'} - assert manufacturer.dict(exclude_list=True) == {'founded': 1937, 'id': toyota.id, 'name': 'Toyota'} + manufacturer = await Company.objects.select_related("cars").get( + name="Toyota" + ) + assert manufacturer.dict() == { + "cars": [ + { + "aircon_type": "Manual", + "gearbox_type": "Manual", + "gears": 5, + "id": car1.id, + "name": "Corolla", + "year": 2020, + }, + { + "aircon_type": "Manual", + "gearbox_type": "Manual", + "gears": 5, + "id": car2.id, + "name": "Yaris", + "year": 2019, + }, + ], + "founded": 1937, + "id": toyota.id, + "name": "Toyota", + } + assert manufacturer.dict(exclude_list=True) == { + "founded": 1937, + "id": toyota.id, + "name": "Toyota", + } diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index fd63dd578..97fb21539 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -2,8 +2,6 @@ from typing import List, Optional, Union import databases -from pydantic import Field - import ormar import pydantic import pytest @@ -11,6 +9,7 @@ from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient +from pydantic import Field from tests.settings import DATABASE_URL @@ -114,7 +113,9 @@ async def test_all_endpoints(): assert response.status_code == 200 category2 = response.json() - response = await client.post("/items/", json={"name": "test", "id": 1, "test_P_or_A": 0}) + response = await client.post( + "/items/", json={"name": "test", "id": 1, "test_P_or_A": 0} + ) assert response.status_code == 200 item = Item(**response.json()) assert item.pk is not None @@ -156,7 +157,7 @@ def test_schema_modification(): "name": "string", "pydantic_int": 0, "test_P": [{"a": 0, "b": {"c": "string", "d": "string", "e": "string"}}], - 'test_P_or_A': (0, 'string') + "test_P_or_A": (0, "string"), } schema = Category.model_json_schema() @@ -171,7 +172,7 @@ def test_schema_modification(): "test_P": [ {"a": 0, "b": {"c": "string", "d": "string", "e": "string"}} ], - 'test_P_or_A': (0, 'string') + "test_P_or_A": (0, "string"), } ], } diff --git a/tests/test_fastapi/test_inheritance_concrete_fastapi.py b/tests/test_fastapi/test_inheritance_concrete_fastapi.py index fae0c143c..0c3fbd180 100644 --- a/tests/test_fastapi/test_inheritance_concrete_fastapi.py +++ b/tests/test_fastapi/test_inheritance_concrete_fastapi.py @@ -8,7 +8,7 @@ from httpx import AsyncClient from tests.settings import DATABASE_URL -from tests.test_inheritance_and_pydantic_generation.test_inheritance_concrete import ( # type: ignore +from tests.test_inheritance_and_pydantic_generation.test_inheritance_concrete import ( # noqa: E501 Bus, Bus2, Category, diff --git a/tests/test_fastapi/test_inheritance_mixins_fastapi.py b/tests/test_fastapi/test_inheritance_mixins_fastapi.py index 4347718f8..c57d88f1b 100644 --- a/tests/test_fastapi/test_inheritance_mixins_fastapi.py +++ b/tests/test_fastapi/test_inheritance_mixins_fastapi.py @@ -7,7 +7,7 @@ from httpx import AsyncClient from tests.settings import DATABASE_URL -from tests.test_inheritance_and_pydantic_generation.test_inheritance_mixins import ( # type: ignore +from tests.test_inheritance_and_pydantic_generation.test_inheritance_mixins import ( # noqa: E501 Category, Subject, metadata, diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index efdfa6ae9..225fb6ffb 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -518,6 +518,7 @@ async def test_model_first(): assert await User.objects.order_by("name").first() == jane + @pytest.mark.asyncio async def test_model_choices(): """Test that choices work properly for various types of fields.""" diff --git a/tests/test_model_definition/test_overwriting_pydantic_field_type.py b/tests/test_model_definition/test_overwriting_pydantic_field_type.py index 92d97acee..cd2bb3f45 100644 --- a/tests/test_model_definition/test_overwriting_pydantic_field_type.py +++ b/tests/test_model_definition/test_overwriting_pydantic_field_type.py @@ -21,7 +21,9 @@ class OverwriteTest(ormar.Model): id: int = ormar.Integer(primary_key=True) my_int: int = ormar.Integer(overwrite_pydantic_type=PositiveInt) - constraint_dict: Json = ormar.JSON(overwrite_pydantic_type=Optional[Json[Dict[str, int]]]) # type: ignore + constraint_dict: Json = ormar.JSON( + overwrite_pydantic_type=Optional[Json[Dict[str, int]]] + ) # type: ignore @pytest.fixture(autouse=True, scope="module") diff --git a/tests/test_relations/test_replacing_models_with_copy.py b/tests/test_relations/test_replacing_models_with_copy.py index 8d905d2e4..240caa0b5 100644 --- a/tests/test_relations/test_replacing_models_with_copy.py +++ b/tests/test_relations/test_replacing_models_with_copy.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional, Tuple, Union +from typing import Any, Optional, Tuple, Union import databases import ormar @@ -53,6 +53,7 @@ def create_test_database(): @pytest.mark.asyncio async def test_model_is_replaced_by_a_copy(): assert Album.model_fields["tracks"].annotation.__args__[1] != Track - assert Album.model_fields["tracks"].annotation.__args__[1].model_fields.keys() == Track.model_fields.keys() - - + assert ( + Album.model_fields["tracks"].annotation.__args__[1].model_fields.keys() + == Track.model_fields.keys() + ) From ae60373bd1113653b681e38d9c32cf10e78d91c3 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 18:50:36 +0100 Subject: [PATCH 34/95] fix pyproject --- poetry.lock | 2 +- pyproject.toml | 47 ++++++++++++++++++++++------------------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/poetry.lock b/poetry.lock index c8a16f377..295bcc91f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2475,4 +2475,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "90ceff224348336d1d521751ba9a001d77fd31bbaedd0750733365e428ae32ad" +content-hash = "2ea518d4e70150f1a28dd6b230ac00fd3b49d011a77435112fc489e3ce32ad13" diff --git a/pyproject.toml b/pyproject.toml index 0b63a7cbf..e440fd968 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,8 +69,27 @@ python = "<3.8" version = ">=3.1" python = "<3.8" +[tool.poetry.extras] +postgresql = ["asyncpg", "psycopg2-binary"] +postgres = ["asyncpg", "psycopg2-binary"] +aiopg = ["aiopg", "psycopg2-binary"] +mysql = ["aiomysql", "PyMySQL"] +sqlite = ["aiosqlite"] +orjson = ["orjson"] +crypto = ["cryptography"] +all = [ + "aiosqlite", + "asyncpg", + "aiopg", + "psycopg2-binary", + "aiomysql", + "mysqlclient", + "PyMySQL", + "orjson", + "cryptography", +] -[tool.poetry.dev-dependencies] +[tool.poetry.group.dev.dependencies] # Testing pytest = "^7.4.0" pytest-cov = "^4.0.0" @@ -78,7 +97,7 @@ codecov = "^2.1.13" pytest-asyncio = "^0.21.0" fastapi = ">=0.105.0" -black = "^23.1.0" +black = "^24.1.0" ruff = "^0.0.275" # types @@ -110,31 +129,9 @@ pytest-benchmark = "^4.0.0" nest-asyncio = "^1.5.6" pre-commit = "^2.21.0" - -[tool.poetry.extras] -postgresql = ["asyncpg", "psycopg2-binary"] -postgres = ["asyncpg", "psycopg2-binary"] -aiopg = ["aiopg", "psycopg2-binary"] -mysql = ["aiomysql", "PyMySQL"] -sqlite = ["aiosqlite"] -orjson = ["orjson"] -crypto = ["cryptography"] -all = [ - "aiosqlite", - "asyncpg", - "aiopg", - "psycopg2-binary", - "aiomysql", - "mysqlclient", - "PyMySQL", - "orjson", - "cryptography", -] - -[tool.poetry.group.dev.dependencies] httpx = "^0.24.1" asgi-lifespan = "^2.1.0" -black = "^24.1.0" + [build-system] requires = ["poetry-core>=1.0.0"] From 2988c9ede7b29b959c9c63aea698f4a295168080 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 18:53:14 +0100 Subject: [PATCH 35/95] pin py ver in test docs --- .github/workflows/test_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_docs.yml b/.github/workflows/test_docs.yml index 87e0b26b7..7124e3af7 100644 --- a/.github/workflows/test_docs.yml +++ b/.github/workflows/test_docs.yml @@ -20,7 +20,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} + python-version: 3.11 - name: Install dependencies run: | python -m pip install poetry==1.4.2 From 81347972f76896cf4a2a2172c5392c67884722a5 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 18:55:44 +0100 Subject: [PATCH 36/95] change dir in test docs --- scripts/test_docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test_docs.sh b/scripts/test_docs.sh index be49f6d90..ce57fdb2c 100644 --- a/scripts/test_docs.sh +++ b/scripts/test_docs.sh @@ -9,4 +9,4 @@ fi set -x -PYTHONPATH=. ${PREFIX}pytest --ignore venv --cov=${PACKAGE} --cov=tests --cov-report=xml --cov-fail-under=100 --cov-report=term-missing tests/ "${@}" +PYTHONPATH=. ${PREFIX}pytest --ignore venv --cov=${PACKAGE} --cov=tests --cov-report=xml --cov-fail-under=100 --cov-report=term-missing docs_src/ "${@}" From a762f8e5fc3466b64ee451a4db8c14717bb80fbc Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 19:01:27 +0100 Subject: [PATCH 37/95] fix pydantic warning hack --- ormar/models/metaclass.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index dbb0f3f83..e3214c32f 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -1,5 +1,6 @@ import copy import sys +from pathlib import Path from typing import ( TYPE_CHECKING, Any, @@ -736,9 +737,11 @@ def __getattr__(self, item: str) -> Any: """ # Ugly workaround for name shadowing warnings in pydantic frame = sys._getframe(1) + file_name = Path(frame.f_code.co_filename) if ( frame.f_code.co_name == "collect_model_fields" - and frame.f_code.co_filename.endswith("pydantic\_internal\_fields.py") + and file_name.name == "_fields.py" + and file_name.parent.parent.name == "pydantic" ): raise AttributeError() if item == "pk": From 7c27c4911818a918d77a64f92ccb8e4cb359d971 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 19:06:23 +0100 Subject: [PATCH 38/95] rm poetry call in test_docs --- docs_src/test_all_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_src/test_all_docs.py b/docs_src/test_all_docs.py index 40ab39333..c1178247c 100644 --- a/docs_src/test_all_docs.py +++ b/docs_src/test_all_docs.py @@ -18,5 +18,5 @@ @pytest.mark.parametrize("filepath", filepaths) def test_all_docs(filepath: str): - result = subprocess.run(["poetry", "run", "python", filepath]) + result = subprocess.run(["python", filepath]) assert result.returncode == 0 From 5e709b6fb23bf6680a1c1a770d356fff763b67e2 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 19:11:58 +0100 Subject: [PATCH 39/95] switch to pathlib in test docs --- docs_src/test_all_docs.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/docs_src/test_all_docs.py b/docs_src/test_all_docs.py index c1178247c..4080e3434 100644 --- a/docs_src/test_all_docs.py +++ b/docs_src/test_all_docs.py @@ -1,19 +1,16 @@ -import os import subprocess +from pathlib import Path import pytest filepaths = [] -root_dir = os.getcwd() -for dirpath, dirnames, filenames in os.walk(root_dir): - for filename in filenames: - if ( - filename.endswith(".py") - and not filename.endswith("__init__.py") - and os.path.join(root_dir, filename) != __file__ - ): - filepath_ = os.path.join(dirpath, filename) - filepaths.append(filepath_) +path = Path(__file__).parent +for p in path.rglob("*"): + print(p.name) +for p in path.rglob("*"): + if p.name.endswith(".py") and not p.name == "__init__.py" and p != Path(__file__): + filepath_ = str(p.resolve()) + filepaths.append(filepath_) @pytest.mark.parametrize("filepath", filepaths) From 9b165d9dddde4c35309b4df9ce79b177cf46ca30 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 26 Jan 2024 19:15:16 +0100 Subject: [PATCH 40/95] remove coverage req test docs --- scripts/test_docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test_docs.sh b/scripts/test_docs.sh index ce57fdb2c..a5dacf6d9 100644 --- a/scripts/test_docs.sh +++ b/scripts/test_docs.sh @@ -9,4 +9,4 @@ fi set -x -PYTHONPATH=. ${PREFIX}pytest --ignore venv --cov=${PACKAGE} --cov=tests --cov-report=xml --cov-fail-under=100 --cov-report=term-missing docs_src/ "${@}" +PYTHONPATH=. ${PREFIX}pytest --ignore venv docs_src/ "${@}" From df852fe7a09a85b43bd02b478bf5c65fc078ca1b Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 29 Jan 2024 20:28:55 +0100 Subject: [PATCH 41/95] fix type check tests, fix part of types --- .github/workflows/type-check.yml | 2 +- Makefile | 2 +- ormar/fields/constraints.py | 4 +- ormar/fields/foreign_key.py | 8 +- ormar/fields/many_to_many.py | 2 +- ormar/fields/model_fields.py | 42 ++--- ormar/fields/parsers.py | 2 +- ormar/fields/sqlalchemy_encrypted.py | 2 +- ormar/fields/through_field.py | 4 +- ormar/models/excludable.py | 4 +- ormar/models/helpers/relations.py | 2 +- ormar/models/helpers/validation.py | 8 +- ormar/models/mixins/excludable_mixin.py | 4 +- ormar/models/mixins/merge_mixin.py | 2 +- ormar/models/mixins/pydantic_mixin.py | 12 +- ormar/models/mixins/relation_mixin.py | 6 +- ormar/models/mixins/save_mixin.py | 5 +- ormar/models/model.py | 12 +- ormar/models/model_row.py | 12 +- ormar/models/newbasemodel.py | 26 +-- ormar/models/ormar_config.py | 2 +- ormar/models/traversible.py | 10 +- ormar/queryset/actions/order_action.py | 4 +- ormar/queryset/clause.py | 6 +- ormar/queryset/field_accessor.py | 6 +- ormar/queryset/join.py | 4 +- ormar/queryset/queryset.py | 46 ++--- ormar/queryset/utils.py | 2 +- ormar/relations/alias_manager.py | 6 +- ormar/relations/querysetproxy.py | 6 +- ormar/relations/relation.py | 2 +- ormar/relations/relation_manager.py | 2 +- poetry.lock | 216 ++++++++++++------------ pyproject.toml | 2 +- 34 files changed, 237 insertions(+), 238 deletions(-) diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml index 025613162..3a28b670c 100644 --- a/.github/workflows/type-check.yml +++ b/.github/workflows/type-check.yml @@ -28,4 +28,4 @@ jobs: env: POETRY_VIRTUALENVS_CREATE: false - name: Type check - run: python -m mypy . --ignore-missing-imports --install-types --non-interactive + run: python -m mypy ormar tests --ignore-missing-imports --install-types --non-interactive diff --git a/Makefile b/Makefile index 8f98fe716..33a086bf6 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ coverage: pytest --cov=ormar --cov=tests --cov-fail-under=100 --cov-report=term-missing tests type_check: - mkdir -p .mypy_cache && poetry run python -m mypy . --ignore-missing-imports --install-types --non-interactive + mkdir -p .mypy_cache && poetry run python -m mypy ormar tests --ignore-missing-imports --install-types --non-interactive lint: poetry run python -m ruff . --fix diff --git a/ormar/fields/constraints.py b/ormar/fields/constraints.py index e2f684093..66a90f004 100644 --- a/ormar/fields/constraints.py +++ b/ormar/fields/constraints.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Optional from sqlalchemy import CheckConstraint, Index, UniqueConstraint @@ -11,7 +11,7 @@ class UniqueColumns(UniqueConstraint): class IndexColumns(Index): - def __init__(self, *args: Any, name: str = None, **kw: Any) -> None: + def __init__(self, *args: Any, name: Optional[str] = None, **kw: Any) -> None: if not name: name = "TEMPORARY_NAME" super().__init__(name, *args, **kw) diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index 8c59496e9..fc5cdb409 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -204,13 +204,13 @@ def ForeignKey(to: ForwardRef, **kwargs: Any) -> "Model": # pragma: no cover def ForeignKey( # type: ignore # noqa CFQ002 to: Union[Type["T"], "ForwardRef"], *, - name: str = None, + name: Optional[str] = None, unique: bool = False, nullable: bool = True, - related_name: str = None, + related_name: Optional[str] = None, virtual: bool = False, - onupdate: Union[ReferentialAction, str] = None, - ondelete: Union[ReferentialAction, str] = None, + onupdate: Union[ReferentialAction, str, None] = None, + ondelete: Union[ReferentialAction, str, None] = None, **kwargs: Any, ) -> "T": """ diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 499c25f6d..7e89eec40 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -90,7 +90,7 @@ def ManyToMany( # type: ignore to: "ToType", through: Optional["ToType"] = None, *, - name: str = None, + name: Optional[str] = None, unique: bool = False, virtual: bool = False, **kwargs: Any, diff --git a/ormar/fields/model_fields.py b/ormar/fields/model_fields.py index c81faf870..ed931c082 100644 --- a/ormar/fields/model_fields.py +++ b/ormar/fields/model_fields.py @@ -167,8 +167,8 @@ def __new__( # type: ignore # noqa CFQ002 cls, *, max_length: int, - min_length: int = None, - regex: str = None, + min_length: Optional[int] = None, + regex: Optional[str] = None, **kwargs: Any ) -> BaseField: # type: ignore kwargs = { @@ -219,9 +219,9 @@ class Integer(ModelFieldFactory, int): def __new__( # type: ignore cls, *, - minimum: int = None, - maximum: int = None, - multiple_of: int = None, + minimum: Optional[int] = None, + maximum: Optional[int] = None, + multiple_of: Optional[int] = None, **kwargs: Any ) -> BaseField: autoincrement = kwargs.pop("autoincrement", None) @@ -300,9 +300,9 @@ class Float(ModelFieldFactory, float): def __new__( # type: ignore cls, *, - minimum: float = None, - maximum: float = None, - multiple_of: int = None, + minimum: Optional[float] = None, + maximum: Optional[float] = None, + multiple_of: Optional[int] = None, **kwargs: Any ) -> BaseField: kwargs = { @@ -562,9 +562,9 @@ class BigInteger(Integer, int): def __new__( # type: ignore cls, *, - minimum: int = None, - maximum: int = None, - multiple_of: int = None, + minimum: Optional[int] = None, + maximum: Optional[int] = None, + multiple_of: Optional[int] = None, **kwargs: Any ) -> BaseField: autoincrement = kwargs.pop("autoincrement", None) @@ -610,9 +610,9 @@ class SmallInteger(Integer, int): def __new__( # type: ignore cls, *, - minimum: int = None, - maximum: int = None, - multiple_of: int = None, + minimum: Optional[int] = None, + maximum: Optional[int] = None, + multiple_of: Optional[int] = None, **kwargs: Any ) -> BaseField: autoincrement = kwargs.pop("autoincrement", None) @@ -658,13 +658,13 @@ class Decimal(ModelFieldFactory, decimal.Decimal): def __new__( # type: ignore # noqa CFQ002 cls, *, - minimum: float = None, - maximum: float = None, - multiple_of: int = None, - precision: int = None, - scale: int = None, - max_digits: int = None, - decimal_places: int = None, + minimum: Optional[float] = None, + maximum: Optional[float] = None, + multiple_of: Optional[int] = None, + precision: Optional[int] = None, + scale: Optional[int] = None, + max_digits: Optional[int] = None, + decimal_places: Optional[int] = None, **kwargs: Any ) -> BaseField: kwargs = { diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index 7b031ced9..6fa2d4aa7 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -21,7 +21,7 @@ def encode_bool(value: bool) -> str: return "true" if value else "false" -def encode_decimal(value: decimal.Decimal, precision: int = None) -> float: +def encode_decimal(value: decimal.Decimal, precision: Optional[int] = None) -> float: return ( round(float(value), precision) if isinstance(value, decimal.Decimal) else value ) diff --git a/ormar/fields/sqlalchemy_encrypted.py b/ormar/fields/sqlalchemy_encrypted.py index 6ff894d14..b9f5a4fb2 100644 --- a/ormar/fields/sqlalchemy_encrypted.py +++ b/ormar/fields/sqlalchemy_encrypted.py @@ -119,7 +119,7 @@ def __init__( self, encrypt_secret: Union[str, Callable], encrypt_backend: EncryptBackends = EncryptBackends.FERNET, - encrypt_custom_backend: Type[EncryptBackend] = None, + encrypt_custom_backend: Optional[Type[EncryptBackend]] = None, **kwargs: Any, ) -> None: _field_type = kwargs.pop("_field_type") diff --git a/ormar/fields/through_field.py b/ormar/fields/through_field.py index d5ece7879..d6d30d6e9 100644 --- a/ormar/fields/through_field.py +++ b/ormar/fields/through_field.py @@ -1,5 +1,5 @@ import sys -from typing import TYPE_CHECKING, Any, Type, Union +from typing import TYPE_CHECKING, Any, Type, Union, Optional from ormar.fields.base import BaseField from ormar.fields.foreign_key import ForeignKeyField @@ -16,7 +16,7 @@ def Through( # noqa CFQ002 - to: "ToType", *, name: str = None, related_name: str = None, **kwargs: Any + to: "ToType", *, name: Optional[str] = None, related_name: Optional[str] = None, **kwargs: Any ) -> Any: """ Despite a name it's a function that returns constructed ThroughField. diff --git a/ormar/models/excludable.py b/ormar/models/excludable.py index ac851d031..7d2dc556c 100644 --- a/ormar/models/excludable.py +++ b/ormar/models/excludable.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import TYPE_CHECKING, Dict, List, Set, Tuple, Type, Union +from typing import TYPE_CHECKING, Dict, List, Set, Tuple, Type, Union, Optional from ormar.queryset.utils import get_relationship_alias_model_and_str @@ -186,7 +186,7 @@ def _traverse_dict( # noqa: CFQ002 source_model: Type["Model"], model_cls: Type["Model"], is_exclude: bool, - related_items: List = None, + related_items: Optional[List] = None, alias: str = "", ) -> None: """ diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index a4f9aefe0..a484f44ef 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -156,7 +156,7 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: def add_field_serializer_for_reverse_relations( - to_model: "Model", related_name: str + to_model: Type["Model"], related_name: str ) -> None: def serialize( self, children: List["BaseModel"], handler: SerializerFunctionWrapHandler diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index bb123baa2..5f572620b 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -8,7 +8,7 @@ List, Set, Type, - Union, + Union, Optional, ) try: @@ -26,7 +26,7 @@ from ormar.fields import BaseField -def generate_model_example(model: Type["Model"], relation_map: Dict = None) -> Dict: +def generate_model_example(model: Type["Model"], relation_map: Optional[Dict] = None) -> Dict: """ Generates example to be included in schema in fastapi. @@ -55,7 +55,7 @@ def generate_model_example(model: Type["Model"], relation_map: Dict = None) -> D def populates_sample_fields_values( - example: Dict[str, Any], name: str, field: "BaseField", relation_map: Dict = None + example: Dict[str, Any], name: str, field: "BaseField", relation_map: Optional[Dict] = None ) -> None: """ Iterates the field and sets fields to sample values @@ -99,7 +99,7 @@ def get_nested_model_example( def generate_pydantic_example( - pydantic_model: Type[pydantic.BaseModel], exclude: Set = None + pydantic_model: Type[pydantic.BaseModel], exclude: Optional[Set] = None ) -> Dict: """ Generates dict with example. diff --git a/ormar/models/mixins/excludable_mixin.py b/ormar/models/mixins/excludable_mixin.py index b9d44eeac..98510f125 100644 --- a/ormar/models/mixins/excludable_mixin.py +++ b/ormar/models/mixins/excludable_mixin.py @@ -9,7 +9,7 @@ Type, TypeVar, Union, - cast, + cast, Optional, ) from ormar.models.excludable import ExcludableItems @@ -35,7 +35,7 @@ class ExcludableMixin(RelationMixin): @staticmethod def get_child( - items: Union[Set, Dict, None], key: str = None + items: Union[Set, Dict, None], key: Optional[str] = None ) -> Union[Set, Dict, None]: """ Used to get nested dictionaries keys if they exists otherwise returns diff --git a/ormar/models/mixins/merge_mixin.py b/ormar/models/mixins/merge_mixin.py index 29f9a5538..3555c3489 100644 --- a/ormar/models/mixins/merge_mixin.py +++ b/ormar/models/mixins/merge_mixin.py @@ -69,7 +69,7 @@ def merge_instances_list(cls, result_rows: List["Model"]) -> List["Model"]: @classmethod def merge_two_instances( - cls, one: "Model", other: "Model", relation_map: Dict = None + cls, one: "Model", other: "Model", relation_map: Optional[Dict] = None ) -> "Model": """ Merges current (other) Model and previous one (one) and returns the current diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index 6a50c1d8f..43cc343a9 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -15,7 +15,8 @@ ) import pydantic -from pydantic.fields import Field +from pydantic._internal._decorators import DecoratorInfos +from pydantic.fields import Field, FieldInfo from ormar.models.mixins.relation_mixin import RelationMixin # noqa: I100, I202 from ormar.queryset.utils import translate_list_to_dict @@ -25,13 +26,14 @@ class PydanticMixin(RelationMixin): __cache__: Dict[str, Type[pydantic.BaseModel]] = {} if TYPE_CHECKING: # pragma: no cover - model_fields: Dict[str, Field] + __pydantic_decorators__: DecoratorInfos + model_fields: Dict[str, FieldInfo] _skip_ellipsis: Callable _get_not_excluded_fields: Callable @classmethod def get_pydantic( - cls, *, include: Union[Set, Dict] = None, exclude: Union[Set, Dict] = None + cls, *, include: Union[Set, Dict, None] = None, exclude: Union[Set, Dict, None] = None ) -> Type[pydantic.BaseModel]: """ Returns a pydantic model out of ormar model. @@ -55,8 +57,8 @@ def get_pydantic( def _convert_ormar_to_pydantic( cls, relation_map: Dict[str, Any], - include: Union[Set, Dict] = None, - exclude: Union[Set, Dict] = None, + include: Union[Set, Dict, None] = None, + exclude: Union[Set, Dict, None] = None, ) -> Type[pydantic.BaseModel]: if include and isinstance(include, Set): include = translate_list_to_dict(include) diff --git a/ormar/models/mixins/relation_mixin.py b/ormar/models/mixins/relation_mixin.py index 9eacaab89..cf2a0af3c 100644 --- a/ormar/models/mixins/relation_mixin.py +++ b/ormar/models/mixins/relation_mixin.py @@ -119,9 +119,9 @@ def _extract_db_related_names(cls) -> Set: @classmethod def _iterate_related_models( # noqa: CCR001 cls, - node_list: NodeList = None, - parsed_map: Dict = None, - source_relation: str = None, + node_list: Optional[NodeList] = None, + parsed_map: Optional[Dict] = None, + source_relation: Optional[str] = None, recurrent: bool = False, ) -> List[str]: """ diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index f7eb7a1f3..d52a3df86 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -15,6 +15,7 @@ import pydantic from pydantic.plugin._schema_validator import create_schema_validator +from pydantic_core import CoreSchema, SchemaValidator import ormar # noqa: I100, I202 from ormar.exceptions import ModelPersistenceError @@ -32,11 +33,11 @@ class SavePrepareMixin(RelationMixin, AliasMixin): """ if TYPE_CHECKING: # pragma: nocover - _choices_fields: Optional[Set] _skip_ellipsis: Callable _json_fields: Set[str] _bytes_fields: Set[str] - __fields__: Dict[str, pydantic.fields.Field] + __pydantic_core_schema__: CoreSchema + __ormar_fields_validators__: Dict[str, SchemaValidator] @classmethod def prepare_model_to_save(cls, new_kwargs: dict) -> dict: diff --git a/ormar/models/model.py b/ormar/models/model.py index e354b23c7..db2ec0321 100644 --- a/ormar/models/model.py +++ b/ormar/models/model.py @@ -114,10 +114,10 @@ async def save_related( # noqa: CCR001, CFQ002 self, follow: bool = False, save_all: bool = False, - relation_map: Dict = None, - exclude: Union[Set, Dict] = None, + relation_map: Optional[Dict] = None, + exclude: Union[Set, Dict, None] = None, update_count: int = 0, - previous_model: "Model" = None, + previous_model: Optional["Model"] = None, relation_field: Optional["ForeignKeyField"] = None, ) -> int: """ @@ -213,7 +213,7 @@ async def save_related( # noqa: CCR001, CFQ002 return update_count - async def update(self: T, _columns: List[str] = None, **kwargs: Any) -> T: + async def update(self: T, _columns: Optional[List[str]] = None, **kwargs: Any) -> T: """ Performs update of Model instance in the database. Fields can be updated before or you can pass them as kwargs. @@ -302,8 +302,8 @@ async def load(self: T) -> T: async def load_all( self: T, follow: bool = False, - exclude: Union[List, str, Set, Dict] = None, - order_by: Union[List, str] = None, + exclude: Union[List, str, Set, Dict, None] = None, + order_by: Union[List, str, None] = None, ) -> T: """ Allow to refresh existing Models fields from database. diff --git a/ormar/models/model_row.py b/ormar/models/model_row.py index 6ff4c4f1b..db0d2ce25 100644 --- a/ormar/models/model_row.py +++ b/ormar/models/model_row.py @@ -21,13 +21,13 @@ def from_row( # noqa: CFQ002 cls, row: ResultProxy, source_model: Type["Model"], - select_related: List = None, + select_related: Optional[List] = None, related_models: Any = None, - related_field: "ForeignKeyField" = None, - excludable: ExcludableItems = None, + related_field: Optional["ForeignKeyField"] = None, + excludable: Optional[ExcludableItems] = None, current_relation_str: str = "", proxy_source_model: Optional[Type["Model"]] = None, - used_prefixes: List[str] = None, + used_prefixes: Optional[List[str]] = None, ) -> Optional["Model"]: """ Model method to convert raw sql row from database into ormar.Model instance. @@ -153,8 +153,8 @@ def _populate_nested_models_from_row( # noqa: CFQ002 excludable: ExcludableItems, table_prefix: str, used_prefixes: List[str], - current_relation_str: str = None, - proxy_source_model: Type["Model"] = None, + current_relation_str: Optional[str] = None, + proxy_source_model: Optional[Type["Model"]] = None, ) -> dict: """ Traverses structure of related models and populates the nested models diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 2ce0a535c..cca1ba111 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -42,7 +42,7 @@ from ormar.relations.relation_manager import RelationsManager if TYPE_CHECKING: # pragma no cover - from ormar.models import Model + from ormar.models import Model, OrmarConfig from ormar.signals import SignalEmitter T = TypeVar("T", bound="NewBaseModel") @@ -77,13 +77,7 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass if TYPE_CHECKING: # pragma no cover pk: Any - __model_fields__: Dict[str, BaseField] - __table__: sqlalchemy.Table - __pydantic_model__: Type[BaseModel] - __pkname__: str - __tablename__: str - __metadata__: sqlalchemy.MetaData - __database__: databases.Database + model_fields: Dict[str, BaseField] __relation_map__: Optional[List[str]] __cached_hash__: Optional[int] _orm_relationship_manager: AliasManager @@ -93,12 +87,10 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass _related_names: Optional[Set] _through_names: Optional[Set] _related_names_hash: str - _choices_fields: Set - _pydantic_fields: Set _quick_access_fields: Set _json_fields: Set _bytes_fields: Set - Meta: ModelMeta + ormar_config: OrmarConfig # noinspection PyMissingConstructor def __init__(self, *args: Any, **kwargs: Any) -> None: # type: ignore @@ -634,7 +626,7 @@ def populate_through_models( model_dict: Dict, include: Union[Set, Dict], exclude: Union[Set, Dict], - relation_map: Dict = None, + relation_map: Optional[Dict] = None, ) -> None: """ Populates through models with values from dict representation. @@ -779,8 +771,8 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 def dict( # type: ignore # noqa A003 self, *, - include: Union[Set, Dict] = None, - exclude: Union[Set, Dict] = None, + include: Union[Set, Dict, None] = None, + exclude: Union[Set, Dict, None] = None, by_alias: bool = False, exclude_unset: bool = False, exclude_defaults: bool = False, @@ -788,7 +780,7 @@ def dict( # type: ignore # noqa A003 exclude_primary_keys: bool = False, exclude_through_models: bool = False, exclude_list: bool = False, - relation_map: Dict = None, + relation_map: Optional[Dict] = None, ) -> "DictStrAny": # noqa: A003' """ @@ -875,8 +867,8 @@ def dict( # type: ignore # noqa A003 def json( # type: ignore # noqa A003 self, *, - include: Union[Set, Dict] = None, - exclude: Union[Set, Dict] = None, + include: Union[Set, Dict, None] = None, + exclude: Union[Set, Dict, None] = None, by_alias: bool = False, exclude_unset: bool = False, exclude_defaults: bool = False, diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index 16b28a6a7..dd99a488b 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -62,7 +62,7 @@ def copy( database=database or self.database, tablename=tablename, order_by=order_by, - abstract=abstract, + abstract=abstract or self.abstract, exclude_parent_fields=exclude_parent_fields, queryset_class=queryset_class or self.queryset_class, extra=extra or self.extra, diff --git a/ormar/models/traversible.py b/ormar/models/traversible.py index 6194cea76..0bb323796 100644 --- a/ormar/models/traversible.py +++ b/ormar/models/traversible.py @@ -18,8 +18,8 @@ def __getitem__(self, item: Any) -> Any: def add( self, node_class: Type["RelationMixin"], - relation_name: str = None, - parent_node: "Node" = None, + relation_name: Optional[str] = None, + parent_node: Optional["Node"] = None, ) -> "Node": """ Adds new Node or returns the existing one @@ -50,7 +50,7 @@ def find( self, node_class: Type["RelationMixin"], relation_name: Optional[str] = None, - parent_node: "Node" = None, + parent_node: Optional["Node"] = None, ) -> Optional["Node"]: """ Searches for existing node with given parameters @@ -78,8 +78,8 @@ class Node: def __init__( self, node_class: Type["RelationMixin"], - relation_name: str = None, - parent_node: "Node" = None, + relation_name: Optional[str] = None, + parent_node: Optional["Node"] = None, ) -> None: self.relation_name = relation_name self.node_class = node_class diff --git a/ormar/queryset/actions/order_action.py b/ormar/queryset/actions/order_action.py index 458cdad7c..b6af3bf8a 100644 --- a/ormar/queryset/actions/order_action.py +++ b/ormar/queryset/actions/order_action.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Type +from typing import TYPE_CHECKING, Type, Optional import sqlalchemy from sqlalchemy import text @@ -20,7 +20,7 @@ class OrderAction(QueryAction): """ def __init__( - self, order_str: str, model_cls: Type["Model"], alias: str = None + self, order_str: str, model_cls: Type["Model"], alias: Optional[str] = None ) -> None: self.direction: str = "" super().__init__(query_str=order_str, model_cls=model_cls) diff --git a/ormar/queryset/clause.py b/ormar/queryset/clause.py index a23bb0b6a..3f88c009f 100644 --- a/ormar/queryset/clause.py +++ b/ormar/queryset/clause.py @@ -1,7 +1,7 @@ import itertools from dataclasses import dataclass from enum import Enum -from typing import TYPE_CHECKING, Any, Generator, List, Tuple, Type +from typing import TYPE_CHECKING, Any, Generator, List, Tuple, Type, Optional import sqlalchemy @@ -52,8 +52,8 @@ def __invert__(self) -> "FilterGroup": def resolve( self, model_cls: Type["Model"], - select_related: List = None, - filter_clauses: List = None, + select_related: Optional[List] = None, + filter_clauses: Optional[List] = None, ) -> Tuple[List[FilterAction], List[str]]: """ Resolves the FilterGroups actions to use proper target model, replace diff --git a/ormar/queryset/field_accessor.py b/ormar/queryset/field_accessor.py index 2ff557a21..e222783e6 100644 --- a/ormar/queryset/field_accessor.py +++ b/ormar/queryset/field_accessor.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, Type, cast +from typing import TYPE_CHECKING, Any, Type, cast, Optional from ormar.queryset.actions import OrderAction from ormar.queryset.actions.filter_action import METHODS_TO_OPERATORS @@ -17,8 +17,8 @@ class FieldAccessor: def __init__( self, source_model: Type["Model"], - field: "BaseField" = None, - model: Type["Model"] = None, + field: Optional["BaseField"] = None, + model: Optional[Type["Model"]] = None, access_chain: str = "", ) -> None: self._source_model = source_model diff --git a/ormar/queryset/join.py b/ormar/queryset/join.py index 2afeb624a..acbd79176 100644 --- a/ormar/queryset/join.py +++ b/ormar/queryset/join.py @@ -27,8 +27,8 @@ def __init__( # noqa: CFQ002 relation_str: str, related_models: Any = None, own_alias: str = "", - source_model: Type["Model"] = None, - already_sorted: Dict = None, + source_model: Optional[Type["Model"]] = None, + already_sorted: Optional[Dict] = None, ) -> None: self.relation_name = relation_name self.related_models = related_models or [] diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index 92bfd1d62..021b7a2fa 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -60,14 +60,14 @@ class QuerySet(Generic[T]): def __init__( # noqa CFQ002 self, model_cls: Optional[Type["T"]] = None, - filter_clauses: List = None, - exclude_clauses: List = None, - select_related: List = None, - limit_count: int = None, - offset: int = None, - excludable: "ExcludableItems" = None, - order_bys: List = None, - prefetch_related: List = None, + filter_clauses: Optional[List] = None, + exclude_clauses: Optional[List] = None, + select_related: Optional[List] = None, + limit_count: Optional[int] = None, + offset: Optional[int] = None, + excludable: Optional["ExcludableItems"] = None, + order_bys: Optional[List] = None, + prefetch_related: Optional[List] = None, limit_raw_sql: bool = False, proxy_source_model: Optional[Type["Model"]] = None, ) -> None: @@ -109,15 +109,15 @@ def model(self) -> Type["T"]: def rebuild_self( # noqa: CFQ002 self, - filter_clauses: List = None, - exclude_clauses: List = None, - select_related: List = None, - limit_count: int = None, - offset: int = None, - excludable: "ExcludableItems" = None, - order_bys: List = None, - prefetch_related: List = None, - limit_raw_sql: bool = None, + filter_clauses: Optional[List] = None, + exclude_clauses: Optional[List] = None, + select_related: Optional[List] = None, + limit_count: Optional[int] = None, + offset: Optional[int] = None, + excludable: Optional["ExcludableItems"] = None, + order_bys: Optional[List] = None, + prefetch_related: Optional[List] = None, + limit_raw_sql: Optional[bool] = None, proxy_source_model: Optional[Type["Model"]] = None, ) -> "QuerySet": """ @@ -265,7 +265,7 @@ def table(self) -> sqlalchemy.Table: return self.model_meta.table def build_select_expression( - self, limit: int = None, offset: int = None, order_bys: List = None + self, limit: Optional[int] = None, offset: Optional[int] = None, order_bys: Optional[List] = None ) -> sqlalchemy.sql.select: """ Constructs the actual database query used in the QuerySet. @@ -588,7 +588,7 @@ def order_by(self, columns: Union[List, str, OrderAction]) -> "QuerySet[T]": async def values( self, - fields: Union[List, str, Set, Dict] = None, + fields: Union[List, str, Set, Dict, None] = None, exclude_through: bool = False, _as_dict: bool = True, _flatten: bool = False, @@ -643,7 +643,7 @@ async def values( async def values_list( self, - fields: Union[List, str, Set, Dict] = None, + fields: Union[List, str, Set, Dict, None] = None, flatten: bool = False, exclude_through: bool = False, ) -> List: @@ -857,7 +857,7 @@ def paginate(self, page: int, page_size: int = 20) -> "QuerySet[T]": query_offset = (page - 1) * page_size return self.rebuild_self(limit_count=limit_count, offset=query_offset) - def limit(self, limit_count: int, limit_raw_sql: bool = None) -> "QuerySet[T]": + def limit(self, limit_count: int, limit_raw_sql: Optional[bool] = None) -> "QuerySet[T]": """ You can limit the results to desired number of parent models. @@ -874,7 +874,7 @@ def limit(self, limit_count: int, limit_raw_sql: bool = None) -> "QuerySet[T]": limit_raw_sql = self.limit_sql_raw if limit_raw_sql is None else limit_raw_sql return self.rebuild_self(limit_count=limit_count, limit_raw_sql=limit_raw_sql) - def offset(self, offset: int, limit_raw_sql: bool = None) -> "QuerySet[T]": + def offset(self, offset: int, limit_raw_sql: Optional[bool] = None) -> "QuerySet[T]": """ You can also offset the results by desired number of main models. @@ -1158,7 +1158,7 @@ async def bulk_create(self, objects: List["T"]) -> None: obj.set_save_status(True) async def bulk_update( # noqa: CCR001 - self, objects: List["T"], columns: List[str] = None + self, objects: List["T"], columns: Optional[List[str]] = None ) -> None: """ Performs bulk update in one database session to speed up the process. diff --git a/ormar/queryset/utils.py b/ormar/queryset/utils.py index 7bc9365dd..97122d8e6 100644 --- a/ormar/queryset/utils.py +++ b/ormar/queryset/utils.py @@ -236,7 +236,7 @@ def extract_models_to_dict_of_lists( model_type: Type["Model"], models: Sequence["Model"], select_dict: Dict, - extracted: Dict = None, + extracted: Optional[Dict] = None, ) -> Dict: """ Receives a list of models and extracts all of the children and their children diff --git a/ormar/relations/alias_manager.py b/ormar/relations/alias_manager.py index 9787f571e..baf9ba706 100644 --- a/ormar/relations/alias_manager.py +++ b/ormar/relations/alias_manager.py @@ -1,7 +1,7 @@ import string import uuid from random import choices -from typing import TYPE_CHECKING, Any, Dict, List, Type, Union +from typing import TYPE_CHECKING, Any, Dict, List, Type, Union, Optional import sqlalchemy from sqlalchemy import text @@ -59,7 +59,7 @@ def reversed_aliases(self) -> Dict: @staticmethod def prefixed_columns( - alias: str, table: sqlalchemy.Table, fields: List = None + alias: str, table: sqlalchemy.Table, fields: Optional[List] = None ) -> List[text]: """ Creates a list of aliases sqlalchemy text clauses from @@ -106,7 +106,7 @@ def prefixed_table_name(self, alias: str, table: sqlalchemy.Table) -> text: return self._prefixed_tables.setdefault(key, table.alias(full_alias)) def add_relation_type( - self, source_model: Type["Model"], relation_name: str, reverse_name: str = None + self, source_model: Type["Model"], relation_name: str, reverse_name: Optional[str] = None ) -> None: """ Registers the relations defined in ormar models. diff --git a/ormar/relations/querysetproxy.py b/ormar/relations/querysetproxy.py index 62f5882d2..5173fe7b4 100644 --- a/ormar/relations/querysetproxy.py +++ b/ormar/relations/querysetproxy.py @@ -44,7 +44,7 @@ def __init__( relation: "Relation", to: Type["T"], type_: "RelationType", - qryset: "QuerySet[T]" = None, + qryset: Optional["QuerySet[T]"] = None, ) -> None: self.relation: "Relation" = relation self._queryset: Optional["QuerySet[T]"] = qryset @@ -287,7 +287,7 @@ async def clear(self, keep_reversed: bool = True) -> int: return await queryset.delete(**kwargs) # type: ignore async def values( - self, fields: Union[List, str, Set, Dict] = None, exclude_through: bool = False + self, fields: Union[List, str, Set, Dict, None] = None, exclude_through: bool = False ) -> List: """ Return a list of dictionaries with column values in order of the fields @@ -309,7 +309,7 @@ async def values( async def values_list( self, - fields: Union[List, str, Set, Dict] = None, + fields: Union[List, str, Set, Dict, None] = None, flatten: bool = False, exclude_through: bool = False, ) -> List: diff --git a/ormar/relations/relation.py b/ormar/relations/relation.py index b65db3035..7c2724d8a 100644 --- a/ormar/relations/relation.py +++ b/ormar/relations/relation.py @@ -48,7 +48,7 @@ def __init__( type_: RelationType, field_name: str, to: Type["T"], - through: Type["Model"] = None, + through: Optional[Type["Model"]] = None, ) -> None: """ Initialize the Relation and keep the related models either as instances of diff --git a/ormar/relations/relation_manager.py b/ormar/relations/relation_manager.py index ad37e625a..368661c12 100644 --- a/ormar/relations/relation_manager.py +++ b/ormar/relations/relation_manager.py @@ -16,7 +16,7 @@ class RelationsManager: def __init__( self, - related_fields: List["ForeignKeyField"] = None, + related_fields: Optional[List["ForeignKeyField"]] = None, owner: Optional["Model"] = None, ) -> None: self.owner = proxy(owner) diff --git a/poetry.lock b/poetry.lock index 295bcc91f..00f0adb70 100644 --- a/poetry.lock +++ b/poetry.lock @@ -172,34 +172,34 @@ test = ["flake8 (>=5.0.4,<5.1.0)", "uvloop (>=0.15.3)"] [[package]] name = "black" -version = "24.1.0" +version = "24.1.1" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "black-24.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94d5280d020dadfafc75d7cae899609ed38653d3f5e82e7ce58f75e76387ed3d"}, - {file = "black-24.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aaf9aa85aaaa466bf969e7dd259547f4481b712fe7ee14befeecc152c403ee05"}, - {file = "black-24.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec489cae76eac3f7573629955573c3a0e913641cafb9e3bfc87d8ce155ebdb29"}, - {file = "black-24.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5a0100b4bdb3744dd68412c3789f472d822dc058bb3857743342f8d7f93a5a7"}, - {file = "black-24.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6cc5a6ba3e671cfea95a40030b16a98ee7dc2e22b6427a6f3389567ecf1b5262"}, - {file = "black-24.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0e367759062dcabcd9a426d12450c6d61faf1704a352a49055a04c9f9ce8f5a"}, - {file = "black-24.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be305563ff4a2dea813f699daaffac60b977935f3264f66922b1936a5e492ee4"}, - {file = "black-24.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a8977774929b5db90442729f131221e58cc5d8208023c6af9110f26f75b6b20"}, - {file = "black-24.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d74d4d0da276fbe3b95aa1f404182562c28a04402e4ece60cf373d0b902f33a0"}, - {file = "black-24.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39addf23f7070dbc0b5518cdb2018468ac249d7412a669b50ccca18427dba1f3"}, - {file = "black-24.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:827a7c0da520dd2f8e6d7d3595f4591aa62ccccce95b16c0e94bb4066374c4c2"}, - {file = "black-24.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:0cd59d01bf3306ff7e3076dd7f4435fcd2fafe5506a6111cae1138fc7de52382"}, - {file = "black-24.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf8dd261ee82df1abfb591f97e174345ab7375a55019cc93ad38993b9ff5c6ad"}, - {file = "black-24.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:82d9452aeabd51d1c8f0d52d4d18e82b9f010ecb30fd55867b5ff95904f427ff"}, - {file = "black-24.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9aede09f72b2a466e673ee9fca96e4bccc36f463cac28a35ce741f0fd13aea8b"}, - {file = "black-24.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:780f13d03066a7daf1707ec723fdb36bd698ffa29d95a2e7ef33a8dd8fe43b5c"}, - {file = "black-24.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a15670c650668399c4b5eae32e222728185961d6ef6b568f62c1681d57b381ba"}, - {file = "black-24.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1e0fa70b8464055069864a4733901b31cbdbe1273f63a24d2fa9d726723d45ac"}, - {file = "black-24.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fa8d9aaa22d846f8c0f7f07391148e5e346562e9b215794f9101a8339d8b6d8"}, - {file = "black-24.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:f0dfbfbacfbf9cd1fac7a5ddd3e72510ffa93e841a69fcf4a6358feab1685382"}, - {file = "black-24.1.0-py3-none-any.whl", hash = "sha256:5134a6f6b683aa0a5592e3fd61dd3519d8acd953d93e2b8b76f9981245b65594"}, - {file = "black-24.1.0.tar.gz", hash = "sha256:30fbf768cd4f4576598b1db0202413fafea9a227ef808d1a12230c643cefe9fc"}, + {file = "black-24.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2588021038bd5ada078de606f2a804cadd0a3cc6a79cb3e9bb3a8bf581325a4c"}, + {file = "black-24.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a95915c98d6e32ca43809d46d932e2abc5f1f7d582ffbe65a5b4d1588af7445"}, + {file = "black-24.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fa6a0e965779c8f2afb286f9ef798df770ba2b6cee063c650b96adec22c056a"}, + {file = "black-24.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5242ecd9e990aeb995b6d03dc3b2d112d4a78f2083e5a8e86d566340ae80fec4"}, + {file = "black-24.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fc1ec9aa6f4d98d022101e015261c056ddebe3da6a8ccfc2c792cbe0349d48b7"}, + {file = "black-24.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0269dfdea12442022e88043d2910429bed717b2d04523867a85dacce535916b8"}, + {file = "black-24.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3d64db762eae4a5ce04b6e3dd745dcca0fb9560eb931a5be97472e38652a161"}, + {file = "black-24.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:5d7b06ea8816cbd4becfe5f70accae953c53c0e53aa98730ceccb0395520ee5d"}, + {file = "black-24.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e2c8dfa14677f90d976f68e0c923947ae68fa3961d61ee30976c388adc0b02c8"}, + {file = "black-24.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a21725862d0e855ae05da1dd25e3825ed712eaaccef6b03017fe0853a01aa45e"}, + {file = "black-24.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07204d078e25327aad9ed2c64790d681238686bce254c910de640c7cc4fc3aa6"}, + {file = "black-24.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:a83fe522d9698d8f9a101b860b1ee154c1d25f8a82ceb807d319f085b2627c5b"}, + {file = "black-24.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08b34e85170d368c37ca7bf81cf67ac863c9d1963b2c1780c39102187ec8dd62"}, + {file = "black-24.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7258c27115c1e3b5de9ac6c4f9957e3ee2c02c0b39222a24dc7aa03ba0e986f5"}, + {file = "black-24.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40657e1b78212d582a0edecafef133cf1dd02e6677f539b669db4746150d38f6"}, + {file = "black-24.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e298d588744efda02379521a19639ebcd314fba7a49be22136204d7ed1782717"}, + {file = "black-24.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34afe9da5056aa123b8bfda1664bfe6fb4e9c6f311d8e4a6eb089da9a9173bf9"}, + {file = "black-24.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:854c06fb86fd854140f37fb24dbf10621f5dab9e3b0c29a690ba595e3d543024"}, + {file = "black-24.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3897ae5a21ca132efa219c029cce5e6bfc9c3d34ed7e892113d199c0b1b444a2"}, + {file = "black-24.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:ecba2a15dfb2d97105be74bbfe5128bc5e9fa8477d8c46766505c1dda5883aac"}, + {file = "black-24.1.1-py3-none-any.whl", hash = "sha256:5cdc2e2195212208fbcae579b931407c1fa9997584f0a415421748aeafff1168"}, + {file = "black-24.1.1.tar.gz", hash = "sha256:48b5760dcbfe5cf97fd4fba23946681f3a81514c6ab8a45b50da67ac8fbc6c7b"}, ] [package.dependencies] @@ -451,64 +451,64 @@ files = [ [[package]] name = "coverage" -version = "7.4.0" +version = "7.4.1" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a"}, - {file = "coverage-7.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471"}, - {file = "coverage-7.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9"}, - {file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516"}, - {file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5"}, - {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566"}, - {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae"}, - {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43"}, - {file = "coverage-7.4.0-cp310-cp310-win32.whl", hash = "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451"}, - {file = "coverage-7.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137"}, - {file = "coverage-7.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca"}, - {file = "coverage-7.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06"}, - {file = "coverage-7.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505"}, - {file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc"}, - {file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25"}, - {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70"}, - {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09"}, - {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26"}, - {file = "coverage-7.4.0-cp311-cp311-win32.whl", hash = "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614"}, - {file = "coverage-7.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590"}, - {file = "coverage-7.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143"}, - {file = "coverage-7.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2"}, - {file = "coverage-7.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a"}, - {file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446"}, - {file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9"}, - {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd"}, - {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a"}, - {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa"}, - {file = "coverage-7.4.0-cp312-cp312-win32.whl", hash = "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450"}, - {file = "coverage-7.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0"}, - {file = "coverage-7.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e"}, - {file = "coverage-7.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85"}, - {file = "coverage-7.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac"}, - {file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1"}, - {file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba"}, - {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952"}, - {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e"}, - {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105"}, - {file = "coverage-7.4.0-cp38-cp38-win32.whl", hash = "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2"}, - {file = "coverage-7.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555"}, - {file = "coverage-7.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42"}, - {file = "coverage-7.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7"}, - {file = "coverage-7.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9"}, - {file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed"}, - {file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c"}, - {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870"}, - {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058"}, - {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f"}, - {file = "coverage-7.4.0-cp39-cp39-win32.whl", hash = "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932"}, - {file = "coverage-7.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e"}, - {file = "coverage-7.4.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6"}, - {file = "coverage-7.4.0.tar.gz", hash = "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e"}, + {file = "coverage-7.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7"}, + {file = "coverage-7.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b"}, + {file = "coverage-7.4.1-cp310-cp310-win32.whl", hash = "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016"}, + {file = "coverage-7.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018"}, + {file = "coverage-7.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295"}, + {file = "coverage-7.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6"}, + {file = "coverage-7.4.1-cp311-cp311-win32.whl", hash = "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5"}, + {file = "coverage-7.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968"}, + {file = "coverage-7.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581"}, + {file = "coverage-7.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc"}, + {file = "coverage-7.4.1-cp312-cp312-win32.whl", hash = "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74"}, + {file = "coverage-7.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448"}, + {file = "coverage-7.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218"}, + {file = "coverage-7.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad"}, + {file = "coverage-7.4.1-cp38-cp38-win32.whl", hash = "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042"}, + {file = "coverage-7.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d"}, + {file = "coverage-7.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54"}, + {file = "coverage-7.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35"}, + {file = "coverage-7.4.1-cp39-cp39-win32.whl", hash = "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c"}, + {file = "coverage-7.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a"}, + {file = "coverage-7.4.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166"}, + {file = "coverage-7.4.1.tar.gz", hash = "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04"}, ] [package.dependencies] @@ -1179,46 +1179,50 @@ mkdocstrings = ">=0.20" [[package]] name = "mypy" -version = "0.982" +version = "1.8.0" description = "Optional static typing for Python" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, - {file = "mypy-0.982-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41fd1cf9bc0e1c19b9af13a6580ccb66c381a5ee2cf63ee5ebab747a4badeba3"}, - {file = "mypy-0.982-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f793e3dd95e166b66d50e7b63e69e58e88643d80a3dcc3bcd81368e0478b089c"}, - {file = "mypy-0.982-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86ebe67adf4d021b28c3f547da6aa2cce660b57f0432617af2cca932d4d378a6"}, - {file = "mypy-0.982-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:175f292f649a3af7082fe36620369ffc4661a71005aa9f8297ea473df5772046"}, - {file = "mypy-0.982-cp310-cp310-win_amd64.whl", hash = "sha256:8ee8c2472e96beb1045e9081de8e92f295b89ac10c4109afdf3a23ad6e644f3e"}, - {file = "mypy-0.982-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58f27ebafe726a8e5ccb58d896451dd9a662a511a3188ff6a8a6a919142ecc20"}, - {file = "mypy-0.982-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6af646bd46f10d53834a8e8983e130e47d8ab2d4b7a97363e35b24e1d588947"}, - {file = "mypy-0.982-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7aeaa763c7ab86d5b66ff27f68493d672e44c8099af636d433a7f3fa5596d40"}, - {file = "mypy-0.982-cp37-cp37m-win_amd64.whl", hash = "sha256:724d36be56444f569c20a629d1d4ee0cb0ad666078d59bb84f8f887952511ca1"}, - {file = "mypy-0.982-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14d53cdd4cf93765aa747a7399f0961a365bcddf7855d9cef6306fa41de01c24"}, - {file = "mypy-0.982-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26ae64555d480ad4b32a267d10cab7aec92ff44de35a7cd95b2b7cb8e64ebe3e"}, - {file = "mypy-0.982-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6389af3e204975d6658de4fb8ac16f58c14e1bacc6142fee86d1b5b26aa52bda"}, - {file = "mypy-0.982-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b35ce03a289480d6544aac85fa3674f493f323d80ea7226410ed065cd46f206"}, - {file = "mypy-0.982-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6e564f035d25c99fd2b863e13049744d96bd1947e3d3d2f16f5828864506763"}, - {file = "mypy-0.982-cp38-cp38-win_amd64.whl", hash = "sha256:cebca7fd333f90b61b3ef7f217ff75ce2e287482206ef4a8b18f32b49927b1a2"}, - {file = "mypy-0.982-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a705a93670c8b74769496280d2fe6cd59961506c64f329bb179970ff1d24f9f8"}, - {file = "mypy-0.982-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75838c649290d83a2b83a88288c1eb60fe7a05b36d46cbea9d22efc790002146"}, - {file = "mypy-0.982-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91781eff1f3f2607519c8b0e8518aad8498af1419e8442d5d0afb108059881fc"}, - {file = "mypy-0.982-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa97b9ddd1dd9901a22a879491dbb951b5dec75c3b90032e2baa7336777363b"}, - {file = "mypy-0.982-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a692a8e7d07abe5f4b2dd32d731812a0175626a90a223d4b58f10f458747dd8a"}, - {file = "mypy-0.982-cp39-cp39-win_amd64.whl", hash = "sha256:eb7a068e503be3543c4bd329c994103874fa543c1727ba5288393c21d912d795"}, - {file = "mypy-0.982-py3-none-any.whl", hash = "sha256:1021c241e8b6e1ca5a47e4d52601274ac078a89845cfde66c6d5f769819ffa1d"}, - {file = "mypy-0.982.tar.gz", hash = "sha256:85f7a343542dc8b1ed0a888cdd34dca56462654ef23aa673907305b260b3d746"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, + {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, + {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, + {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, + {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, + {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, + {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, + {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, + {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, + {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, + {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, + {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, + {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, + {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, + {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, + {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, + {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, + {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, ] [package.dependencies] -mypy-extensions = ">=0.4.3" +mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" +typing-extensions = ">=4.1.0" [package.extras] dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] reports = ["lxml"] [[package]] @@ -2475,4 +2479,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "2ea518d4e70150f1a28dd6b230ac00fd3b49d011a77435112fc489e3ce32ad13" +content-hash = "0e2c8f7250939c5c4bff34bff3f06123668a8808b47ed6b52bc18dba1a80391f" diff --git a/pyproject.toml b/pyproject.toml index e440fd968..50e52d876 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,7 +101,7 @@ black = "^24.1.0" ruff = "^0.0.275" # types -mypy = "^0.982" +mypy = "^1.8.0" types-ujson = "^5.7.0" types-PyMySQL = "^1.0.19" types-ipaddress = "^1.0.1" From 7d1e9bc6514b601b290b0d166a47e33db1eed81c Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 29 Jan 2024 21:07:32 +0100 Subject: [PATCH 42/95] fix/skip next part of types --- ormar/fields/foreign_key.py | 5 ++++- ormar/fields/many_to_many.py | 19 +++++++++++-------- ormar/fields/parsers.py | 6 ++---- ormar/fields/through_field.py | 8 ++++++-- ormar/models/excludable.py | 2 +- ormar/models/helpers/relations.py | 10 +++++----- ormar/models/helpers/validation.py | 12 +++++++++--- ormar/models/metaclass.py | 6 +++--- ormar/models/mixins/excludable_mixin.py | 3 ++- ormar/models/mixins/pydantic_mixin.py | 7 +++++-- ormar/models/mixins/save_mixin.py | 5 ++--- ormar/models/newbasemodel.py | 9 +++------ ormar/queryset/actions/order_action.py | 2 +- ormar/queryset/actions/select_action.py | 4 ++-- ormar/queryset/clause.py | 2 +- ormar/queryset/field_accessor.py | 2 +- ormar/queryset/queries/query.py | 2 +- ormar/queryset/queryset.py | 13 ++++++++++--- ormar/relations/alias_manager.py | 7 +++++-- ormar/relations/querysetproxy.py | 4 +++- tests/test_fastapi/test_fastapi_docs.py | 2 +- tests/test_model_definition/test_columns.py | 4 ++-- tests/test_model_definition/test_models.py | 6 +++--- 23 files changed, 83 insertions(+), 57 deletions(-) diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index fc5cdb409..510c7bb10 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -88,7 +88,10 @@ def create_dummy_model( def populate_fk_params_based_on_to_model( - to: Type["T"], nullable: bool, onupdate: str = None, ondelete: str = None + to: Type["T"], + nullable: bool, + onupdate: Optional[str] = None, + ondelete: Optional[str] = None, ) -> Tuple[Any, List, Any, Any]: """ Based on target to model to which relation leads to populates the type of the diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 7e89eec40..a58d6e256 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -65,8 +65,12 @@ def populate_m2m_params_based_on_to_model( to_field = to.ormar_config.model_fields[to.ormar_config.pkname] pk_only_model = create_dummy_model(to, to_field) base_type = Union[ - to_field.__type__, to, pk_only_model, List[to], List[pk_only_model] - ] # type: ignore + to_field.__type__, + to, # type: ignore + pk_only_model, # type: ignore + List[to], # type: ignore + List[pk_only_model], # type: ignore + ] __type__ = ( base_type # type: ignore if not nullable @@ -279,12 +283,11 @@ def create_default_through_model(self) -> None: "__module__": self.owner.__module__, "__qualname__": f"{self.owner.__qualname__}.{class_name}", } - new_meta_namespace = { - "tablename": table_name, - "database": self.owner.ormar_config.database, - "metadata": self.owner.ormar_config.metadata, - } - new_meta = ormar.models.ormar_config.OrmarConfig(**new_meta_namespace) + new_meta = ormar.models.ormar_config.OrmarConfig( + tablename=table_name, + database=self.owner.ormar_config.database, + metadata=self.owner.ormar_config.metadata, + ) through_model = type( class_name, (ormar.Model,), diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index 6fa2d4aa7..0bde4e56f 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -39,10 +39,8 @@ def encode_bytes(value: Union[str, bytes], represent_as_string: bool = False) -> def decode_bytes(value: str, represent_as_string: bool = False) -> bytes: if represent_as_string: - value = value if isinstance(value, bytes) else base64.b64decode(value) - else: - value = value if isinstance(value, bytes) else value.encode("utf-8") - return value + return value if isinstance(value, bytes) else base64.b64decode(value) + return value if isinstance(value, bytes) else value.encode("utf-8") def encode_json(value: Any) -> Optional[str]: diff --git a/ormar/fields/through_field.py b/ormar/fields/through_field.py index d6d30d6e9..e494d90f7 100644 --- a/ormar/fields/through_field.py +++ b/ormar/fields/through_field.py @@ -1,5 +1,5 @@ import sys -from typing import TYPE_CHECKING, Any, Type, Union, Optional +from typing import TYPE_CHECKING, Any, Optional, Type, Union from ormar.fields.base import BaseField from ormar.fields.foreign_key import ForeignKeyField @@ -16,7 +16,11 @@ def Through( # noqa CFQ002 - to: "ToType", *, name: Optional[str] = None, related_name: Optional[str] = None, **kwargs: Any + to: "ToType", + *, + name: Optional[str] = None, + related_name: Optional[str] = None, + **kwargs: Any ) -> Any: """ Despite a name it's a function that returns constructed ThroughField. diff --git a/ormar/models/excludable.py b/ormar/models/excludable.py index 7d2dc556c..2759ad093 100644 --- a/ormar/models/excludable.py +++ b/ormar/models/excludable.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import TYPE_CHECKING, Dict, List, Set, Tuple, Type, Union, Optional +from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type, Union from ormar.queryset.utils import get_relationship_alias_model_and_str diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index a484f44ef..cfc2d2d99 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -144,7 +144,7 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: annotation=field_type, source_model_field=model_field.name ) if not model_field.is_multi: - field_type = Union[field_type, List[field_type], None] + field_type = Union[field_type, List[field_type], None] # type: ignore model_field.to.model_fields[related_name] = FieldInfo.from_annotated_attribute( annotation=field_type, default=None ) @@ -159,7 +159,7 @@ def add_field_serializer_for_reverse_relations( to_model: Type["Model"], related_name: str ) -> None: def serialize( - self, children: List["BaseModel"], handler: SerializerFunctionWrapHandler + self: "Model", children: List["Model"], handler: SerializerFunctionWrapHandler ) -> Any: """ Serialize a list of nodes, handling circular references @@ -186,7 +186,7 @@ def serialize( def replace_models_with_copy( annotation: Type, source_model_field: Optional[str] = None -) -> Type: +) -> Any: """ Replaces all models in annotation with their copies to avoid circular references. @@ -199,12 +199,12 @@ def replace_models_with_copy( return create_copy_to_avoid_circular_references(model=annotation) elif hasattr(annotation, "__origin__") and annotation.__origin__ in {list, Union}: if annotation.__origin__ == list: - return List[ + return List[ # type: ignore replace_models_with_copy( annotation=annotation.__args__[0], source_model_field=source_model_field, ) - ] # type: ignore + ] elif annotation.__origin__ == Union: args = annotation.__args__ new_args = [ diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 5f572620b..7dec8aaaa 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -6,9 +6,10 @@ Callable, Dict, List, + Optional, Set, Type, - Union, Optional, + Union, ) try: @@ -26,7 +27,9 @@ from ormar.fields import BaseField -def generate_model_example(model: Type["Model"], relation_map: Optional[Dict] = None) -> Dict: +def generate_model_example( + model: Type["Model"], relation_map: Optional[Dict] = None +) -> Dict: """ Generates example to be included in schema in fastapi. @@ -55,7 +58,10 @@ def generate_model_example(model: Type["Model"], relation_map: Optional[Dict] = def populates_sample_fields_values( - example: Dict[str, Any], name: str, field: "BaseField", relation_map: Optional[Dict] = None + example: Dict[str, Any], + name: str, + field: "BaseField", + relation_map: Optional[Dict] = None, ) -> None: """ Iterates the field and sets fields to sample values diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index e3214c32f..a2e033360 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -339,7 +339,7 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 new_meta.model_fields = copy.deepcopy(through_class.ormar_config.model_fields) new_meta.property_fields = copy.deepcopy(through_class.ormar_config.property_fields) copy_name = through_class.__name__ + attrs.get("__name__", "") - copy_through = type(copy_name, (ormar.Model,), {"ormar_config": new_meta}) + copy_through = cast(Type[ormar.Model], type(copy_name, (ormar.Model,), {"ormar_config": new_meta})) # create new table with copied columns but remove foreign keys # they will be populated later in expanding reverse relation # if hasattr(new_meta, "table"): @@ -578,10 +578,10 @@ def add_field_descriptor( setattr(new_model, name, PydanticDescriptor(name=name)) -def get_serializer(): +def get_serializer() -> Callable: def serialize( self, - value: Optional[pydantic.BaseModel], + value: Optional["Model"], handler: SerializerFunctionWrapHandler, ) -> Any: """ diff --git a/ormar/models/mixins/excludable_mixin.py b/ormar/models/mixins/excludable_mixin.py index 98510f125..f081a2cb9 100644 --- a/ormar/models/mixins/excludable_mixin.py +++ b/ormar/models/mixins/excludable_mixin.py @@ -5,11 +5,12 @@ Dict, List, Mapping, + Optional, Set, Type, TypeVar, Union, - cast, Optional, + cast, ) from ormar.models.excludable import ExcludableItems diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index 43cc343a9..4307aa0fd 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -16,7 +16,7 @@ import pydantic from pydantic._internal._decorators import DecoratorInfos -from pydantic.fields import Field, FieldInfo +from pydantic.fields import FieldInfo from ormar.models.mixins.relation_mixin import RelationMixin # noqa: I100, I202 from ormar.queryset.utils import translate_list_to_dict @@ -33,7 +33,10 @@ class PydanticMixin(RelationMixin): @classmethod def get_pydantic( - cls, *, include: Union[Set, Dict, None] = None, exclude: Union[Set, Dict, None] = None + cls, + *, + include: Union[Set, Dict, None] = None, + exclude: Union[Set, Dict, None] = None, ) -> Type[pydantic.BaseModel]: """ Returns a pydantic model out of ormar model. diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index d52a3df86..f3aa2b2ae 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -13,7 +13,6 @@ cast, ) -import pydantic from pydantic.plugin._schema_validator import create_schema_validator from pydantic_core import CoreSchema, SchemaValidator @@ -37,7 +36,7 @@ class SavePrepareMixin(RelationMixin, AliasMixin): _json_fields: Set[str] _bytes_fields: Set[str] __pydantic_core_schema__: CoreSchema - __ormar_fields_validators__: Dict[str, SchemaValidator] + __ormar_fields_validators__: Optional[Dict[str, SchemaValidator]] @classmethod def prepare_model_to_save(cls, new_kwargs: dict) -> dict: @@ -282,7 +281,7 @@ def _build_individual_schema_validator(cls) -> Any: return cls.__ormar_fields_validators__ @classmethod - def _extract_pydantic_fields(cls): + def _extract_pydantic_fields(cls) -> Any: if cls.__pydantic_core_schema__["type"] == "model": return cls.__pydantic_core_schema__["schema"]["fields"] elif cls.__pydantic_core_schema__["type"] == "definitions": diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index cca1ba111..ef30c6815 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -17,10 +17,8 @@ cast, ) -import databases import pydantic import sqlalchemy -from pydantic import BaseModel import ormar # noqa I100 from ormar.exceptions import ModelError, ModelPersistenceError @@ -33,7 +31,7 @@ populate_meta_sqlalchemy_table_if_required, update_column_definition, ) -from ormar.models.metaclass import ModelMeta, ModelMetaclass +from ormar.models.metaclass import ModelMetaclass from ormar.models.modelproxy import ModelTableProxy from ormar.models.utils import Extra from ormar.queryset.utils import translate_list_to_dict @@ -77,7 +75,6 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass if TYPE_CHECKING: # pragma no cover pk: Any - model_fields: Dict[str, BaseField] __relation_map__: Optional[List[str]] __cached_hash__: Optional[int] _orm_relationship_manager: AliasManager @@ -192,7 +189,7 @@ def __getattr__(self, item: str) -> Any: # TODO: Check __pydantic_extra__ if item == "__pydantic_extra__": return None - return super().__getattr__(item) + return super().__getattr__(item) # type: ignore def __getstate__(self) -> Dict[Any, Any]: state = super().__getstate__() @@ -549,7 +546,7 @@ def update_forward_refs(cls, **localns: Any) -> None: @staticmethod def _get_not_excluded_fields( - fields: Union[List, Set], include: Optional[Dict], exclude: Optional[Dict] + fields: Union[List, Set], include: Union[Set, Dict], exclude: Union[Set, Dict] ) -> List: """ Returns related field names applying on them include and exclude set. diff --git a/ormar/queryset/actions/order_action.py b/ormar/queryset/actions/order_action.py index b6af3bf8a..22c6aeef0 100644 --- a/ormar/queryset/actions/order_action.py +++ b/ormar/queryset/actions/order_action.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Type, Optional +from typing import TYPE_CHECKING, Optional, Type import sqlalchemy from sqlalchemy import text diff --git a/ormar/queryset/actions/select_action.py b/ormar/queryset/actions/select_action.py index 71a864ab0..141b095c3 100644 --- a/ormar/queryset/actions/select_action.py +++ b/ormar/queryset/actions/select_action.py @@ -1,5 +1,5 @@ import decimal -from typing import TYPE_CHECKING, Any, Callable, Type +from typing import TYPE_CHECKING, Any, Callable, Optional, Type import sqlalchemy @@ -20,7 +20,7 @@ class SelectAction(QueryAction): """ def __init__( - self, select_str: str, model_cls: Type["Model"], alias: str = None + self, select_str: str, model_cls: Type["Model"], alias: Optional[str] = None ) -> None: super().__init__(query_str=select_str, model_cls=model_cls) if alias: # pragma: no cover diff --git a/ormar/queryset/clause.py b/ormar/queryset/clause.py index 3f88c009f..0000ac1c2 100644 --- a/ormar/queryset/clause.py +++ b/ormar/queryset/clause.py @@ -1,7 +1,7 @@ import itertools from dataclasses import dataclass from enum import Enum -from typing import TYPE_CHECKING, Any, Generator, List, Tuple, Type, Optional +from typing import TYPE_CHECKING, Any, Generator, List, Optional, Tuple, Type import sqlalchemy diff --git a/ormar/queryset/field_accessor.py b/ormar/queryset/field_accessor.py index e222783e6..3b66905c9 100644 --- a/ormar/queryset/field_accessor.py +++ b/ormar/queryset/field_accessor.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, Type, cast, Optional +from typing import TYPE_CHECKING, Any, Optional, Type, cast from ormar.queryset.actions import OrderAction from ormar.queryset.actions.filter_action import METHODS_TO_OPERATORS diff --git a/ormar/queryset/queries/query.py b/ormar/queryset/queries/query.py index 5a9ec9071..c53b1365a 100644 --- a/ormar/queryset/queries/query.py +++ b/ormar/queryset/queries/query.py @@ -97,7 +97,7 @@ def _pagination_query_required(self) -> bool: and self._select_related ) - def build_select_expression(self) -> Tuple[sqlalchemy.sql.select, List[str]]: + def build_select_expression(self) -> sqlalchemy.sql.select: """ Main entry point from outside (after proper initialization). diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index 021b7a2fa..1ffc4dcb0 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -265,7 +265,10 @@ def table(self) -> sqlalchemy.Table: return self.model_meta.table def build_select_expression( - self, limit: Optional[int] = None, offset: Optional[int] = None, order_bys: Optional[List] = None + self, + limit: Optional[int] = None, + offset: Optional[int] = None, + order_bys: Optional[List] = None, ) -> sqlalchemy.sql.select: """ Constructs the actual database query used in the QuerySet. @@ -857,7 +860,9 @@ def paginate(self, page: int, page_size: int = 20) -> "QuerySet[T]": query_offset = (page - 1) * page_size return self.rebuild_self(limit_count=limit_count, offset=query_offset) - def limit(self, limit_count: int, limit_raw_sql: Optional[bool] = None) -> "QuerySet[T]": + def limit( + self, limit_count: int, limit_raw_sql: Optional[bool] = None + ) -> "QuerySet[T]": """ You can limit the results to desired number of parent models. @@ -874,7 +879,9 @@ def limit(self, limit_count: int, limit_raw_sql: Optional[bool] = None) -> "Quer limit_raw_sql = self.limit_sql_raw if limit_raw_sql is None else limit_raw_sql return self.rebuild_self(limit_count=limit_count, limit_raw_sql=limit_raw_sql) - def offset(self, offset: int, limit_raw_sql: Optional[bool] = None) -> "QuerySet[T]": + def offset( + self, offset: int, limit_raw_sql: Optional[bool] = None + ) -> "QuerySet[T]": """ You can also offset the results by desired number of main models. diff --git a/ormar/relations/alias_manager.py b/ormar/relations/alias_manager.py index baf9ba706..0355f3430 100644 --- a/ormar/relations/alias_manager.py +++ b/ormar/relations/alias_manager.py @@ -1,7 +1,7 @@ import string import uuid from random import choices -from typing import TYPE_CHECKING, Any, Dict, List, Type, Union, Optional +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union import sqlalchemy from sqlalchemy import text @@ -106,7 +106,10 @@ def prefixed_table_name(self, alias: str, table: sqlalchemy.Table) -> text: return self._prefixed_tables.setdefault(key, table.alias(full_alias)) def add_relation_type( - self, source_model: Type["Model"], relation_name: str, reverse_name: Optional[str] = None + self, + source_model: Type["Model"], + relation_name: str, + reverse_name: Optional[str] = None, ) -> None: """ Registers the relations defined in ormar models. diff --git a/ormar/relations/querysetproxy.py b/ormar/relations/querysetproxy.py index 5173fe7b4..7fd3d658d 100644 --- a/ormar/relations/querysetproxy.py +++ b/ormar/relations/querysetproxy.py @@ -287,7 +287,9 @@ async def clear(self, keep_reversed: bool = True) -> int: return await queryset.delete(**kwargs) # type: ignore async def values( - self, fields: Union[List, str, Set, Dict, None] = None, exclude_through: bool = False + self, + fields: Union[List, str, Set, Dict, None] = None, + exclude_through: bool = False, ) -> List: """ Return a list of dictionaries with column values in order of the fields diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index 97fb21539..96a61362a 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -64,7 +64,7 @@ class Item(ormar.Model): name: str = ormar.String(max_length=100) pydantic_int: Optional[int] = None test_P: List[PTestP] = Field(default_factory=list) - test_P_or_A: Union[int, str] = None + test_P_or_A: Union[int, str, None] = None categories = ormar.ManyToMany(Category) diff --git a/tests/test_model_definition/test_columns.py b/tests/test_model_definition/test_columns.py index b426c4ffd..85eae2a97 100644 --- a/tests/test_model_definition/test_columns.py +++ b/tests/test_model_definition/test_columns.py @@ -132,7 +132,7 @@ async def test_model_crud(): @pytest.mark.asyncio -async def test_invalid_enum_field(): +async def test_invalid_enum_field() -> None: async with database: with pytest.raises(ModelDefinitionError): @@ -144,4 +144,4 @@ class Example2(ormar.Model): ) id: int = ormar.Integer(primary_key=True) - size: MyEnum = ormar.Enum(enum_class=[]) + size: MyEnum = ormar.Enum(enum_class=[]) # type: ignore diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index 225fb6ffb..a817f2785 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -159,7 +159,7 @@ class Country(ormar.Model): ) id: int = ormar.Integer(primary_key=True) - name: str = ormar.Enum(enum_class=CountryNameEnum, default="Canada") + name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, default="Canada") taxed: bool = ormar.Boolean(default=True) country_code: int = ormar.Enum(enum_class=CountryCodeEnum, default=1) @@ -172,7 +172,7 @@ class NullableCountry(ormar.Model): ) id: int = ormar.Integer(primary_key=True) - name: str = ormar.Enum(enum_class=CountryNameEnum, nullable=True) + name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, nullable=True) class NotNullableCountry(ormar.Model): @@ -183,7 +183,7 @@ class NotNullableCountry(ormar.Model): ) id: int = ormar.Integer(primary_key=True) - name: str = ormar.Enum(enum_class=CountryNameEnum, nullable=False) + name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, nullable=False) @pytest.fixture(autouse=True, scope="module") From d47132ecb4a1cd5b5666ea95bf68207fc70a1382 Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 29 Jan 2024 21:20:11 +0100 Subject: [PATCH 43/95] fix next part of types --- .../test_inheritance_concrete.py | 29 ++++++++++--------- .../test_inheritance_mixins.py | 7 ++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index 7045f1f5d..efc5beed3 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -1,4 +1,3 @@ -# type: ignore import datetime from collections import Counter from typing import List, Optional @@ -15,6 +14,7 @@ from pydantic import computed_field from sqlalchemy import create_engine +from ormar.relations.relation_proxy import RelationProxy from tests.settings import DATABASE_URL metadata = sa.MetaData() @@ -149,7 +149,7 @@ class Car2(ormar.Model): id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) owner: Person = ormar.ForeignKey(Person, related_name="owned") - co_owners: List[Person] = ormar.ManyToMany(Person, related_name="coowned") + co_owners: RelationProxy[Person] = ormar.ManyToMany(Person, related_name="coowned") created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) @@ -176,12 +176,12 @@ def create_test_database(): metadata.drop_all(engine) -def test_init_of_abstract_model(): +def test_init_of_abstract_model() -> None: with pytest.raises(ModelError): DateFieldsModel() -def test_duplicated_related_name_on_different_model(): +def test_duplicated_related_name_on_different_model() -> None: with pytest.raises(ModelDefinitionError): class Bus3(Car2): # pragma: no cover @@ -191,7 +191,7 @@ class Bus3(Car2): # pragma: no cover max_persons: int = ormar.Integer() -def test_field_redefining_in_concrete_models(): +def test_field_redefining_in_concrete_models() -> None: class RedefinedField(DateFieldsModel): ormar_config = ormar.OrmarConfig( tablename="redefines", @@ -200,7 +200,7 @@ class RedefinedField(DateFieldsModel): ) id: int = ormar.Integer(primary_key=True) - created_date: str = ormar.String(max_length=200, name="creation_date") + created_date: str = ormar.String(max_length=200, name="creation_date") # type: ignore changed_field = RedefinedField.ormar_config.model_fields["created_date"] assert changed_field.ormar_default is None @@ -214,7 +214,7 @@ class RedefinedField(DateFieldsModel): ) -def test_model_subclassing_that_redefines_constraints_column_names(): +def test_model_subclassing_that_redefines_constraints_column_names() -> None: with pytest.raises(ModelDefinitionError): class WrongField2(DateFieldsModel): # pragma: no cover @@ -228,7 +228,7 @@ class WrongField2(DateFieldsModel): # pragma: no cover created_date: str = ormar.String(max_length=200) -def test_model_subclassing_non_abstract_raises_error(): +def test_model_subclassing_non_abstract_raises_error() -> None: with pytest.raises(ModelDefinitionError): class WrongField2(DateFieldsModelNoSubclass): # pragma: no cover @@ -241,7 +241,7 @@ class WrongField2(DateFieldsModelNoSubclass): # pragma: no cover id: int = ormar.Integer(primary_key=True) -def test_params_are_inherited(): +def test_params_are_inherited() -> None: assert Category.ormar_config.metadata == metadata assert Category.ormar_config.database == db assert len(Category.ormar_config.property_fields) == 2 @@ -261,7 +261,7 @@ def round_date_to_seconds( @pytest.mark.asyncio -async def test_fields_inherited_from_mixin(): +async def test_fields_inherited_from_mixin() -> None: async with db: async with db.transaction(force_rollback=True): cat = await Category( @@ -310,6 +310,7 @@ async def test_fields_inherited_from_mixin(): assert round_date_to_seconds(sub2.created_date) == round_date_to_seconds( sub.created_date ) + assert sub2.category is not None assert sub2.category.updated_date is not None assert round_date_to_seconds( sub2.category.created_date @@ -337,7 +338,7 @@ async def test_fields_inherited_from_mixin(): @pytest.mark.asyncio -async def test_inheritance_with_relation(): +async def test_inheritance_with_relation() -> None: async with db: async with db.transaction(force_rollback=True): sam = await Person(name="Sam").save() @@ -386,7 +387,7 @@ async def test_inheritance_with_relation(): @pytest.mark.asyncio -async def test_inheritance_with_multi_relation(): +async def test_inheritance_with_multi_relation() -> None: async with db: async with db.transaction(force_rollback=True): sam = await Person(name="Sam").save() @@ -532,7 +533,7 @@ async def test_inheritance_with_multi_relation(): assert len(unicorns[1].co_owners) == 1 -def test_custom_config(): +def test_custom_config() -> None: # Custom config inherits defaults assert ImmutablePerson.model_config["from_attributes"] is True # Custom config can override defaults @@ -542,6 +543,6 @@ def test_custom_config(): sam.name = "Not Sam" -def test_get_constraint_copy(): +def test_get_constraint_copy() -> None: with pytest.raises(ValueError): get_constraint_copy("INVALID CONSTRAINT") diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py index c643f44ef..65495288d 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py @@ -1,4 +1,3 @@ -# type: ignore import datetime from typing import Optional @@ -56,7 +55,7 @@ def create_test_database(): metadata.drop_all(engine) -def test_field_redefining(): +def test_field_redefining() -> None: class RedefinedField(ormar.Model, DateFieldsMixins): ormar_config = ormar.OrmarConfig( tablename="redefined", @@ -79,7 +78,7 @@ class RedefinedField(ormar.Model, DateFieldsMixins): ) -def test_field_redefining_in_second_raises_error(): +def test_field_redefining_in_second_raises_error() -> None: class OkField(ormar.Model, DateFieldsMixins): # pragma: no cover ormar_config = ormar.OrmarConfig( tablename="oks", @@ -124,7 +123,7 @@ def round_date_to_seconds( @pytest.mark.asyncio -async def test_fields_inherited_from_mixin(): +async def test_fields_inherited_from_mixin() -> None: async with db: async with db.transaction(force_rollback=True): cat = await Category( From 455e8b5b843847a78444d073a1d21ba0108b4c27 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 30 Jan 2024 18:25:06 +0100 Subject: [PATCH 44/95] fix next part of types --- ormar/__init__.py | 2 - ormar/fields/many_to_many.py | 4 +- ormar/fields/sqlalchemy_encrypted.py | 5 +- ormar/models/helpers/pydantic.py | 2 +- ormar/models/metaclass.py | 48 +++++------------- ormar/models/newbasemodel.py | 49 +++++++++++++------ ormar/models/ormar_config.py | 19 +++++-- .../test_inheritance_concrete.py | 11 +++-- .../test_inheritance_mixins.py | 16 +++--- 9 files changed, 79 insertions(+), 77 deletions(-) diff --git a/ormar/__init__.py b/ormar/__init__.py index ef1a8fae2..ae129b7ca 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -76,7 +76,6 @@ # noqa: I100 from ormar.models import ExcludableItems, Extra, Model, OrmarConfig -from ormar.models.metaclass import ModelMeta from ormar.queryset import OrderAction, QuerySet, and_, or_ from ormar.relations import RelationType from ormar.signals import Signal @@ -120,7 +119,6 @@ def __repr__(self) -> str: "ReferentialAction", "QuerySetProtocol", "RelationProtocol", - "ModelMeta", "post_bulk_update", "post_delete", "post_save", diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index a58d6e256..2739eda60 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -64,8 +64,8 @@ def populate_m2m_params_based_on_to_model( """ to_field = to.ormar_config.model_fields[to.ormar_config.pkname] pk_only_model = create_dummy_model(to, to_field) - base_type = Union[ - to_field.__type__, + base_type = Union[ # type: ignore + to_field.__type__, # type: ignore to, # type: ignore pk_only_model, # type: ignore List[to], # type: ignore diff --git a/ormar/fields/sqlalchemy_encrypted.py b/ormar/fields/sqlalchemy_encrypted.py index b9f5a4fb2..dcfb3eeaa 100644 --- a/ormar/fields/sqlalchemy_encrypted.py +++ b/ormar/fields/sqlalchemy_encrypted.py @@ -191,7 +191,10 @@ def process_result_value(self, value: Any, dialect: Dialect) -> Any: additional_parameter = getattr( self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_] ) - return decoder(decrypted_value, additional_parameter) + return decoder( + decrypted_value, + additional_parameter, + ) # type: ignore return decoder(decrypted_value) # type: ignore return self._field_type.__type__(decrypted_value) # type: ignore diff --git a/ormar/models/helpers/pydantic.py b/ormar/models/helpers/pydantic.py index e681076b2..27629b9fe 100644 --- a/ormar/models/helpers/pydantic.py +++ b/ormar/models/helpers/pydantic.py @@ -30,7 +30,7 @@ def create_pydantic_field( :type model_field: ManyToManyField class """ model_field.through.model_fields[field_name] = FieldInfo.from_annotated_attribute( - annotation=Optional[model], default=None + annotation=Optional[model], default=None # type: ignore ) model_field.through.model_rebuild(force=True) diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index a2e033360..6d5f32f60 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -15,7 +15,6 @@ cast, ) -import databases import pydantic import sqlalchemy from pydantic import field_serializer @@ -57,10 +56,8 @@ ) from ormar.models.ormar_config import OrmarConfig from ormar.models.quick_access_views import quick_access_set -from ormar.models.utils import Extra from ormar.queryset import FieldAccessor, QuerySet -from ormar.relations.alias_manager import AliasManager -from ormar.signals import Signal, SignalEmitter +from ormar.signals import Signal if TYPE_CHECKING: # pragma no cover from ormar import Model @@ -70,32 +67,6 @@ PARSED_FIELDS_KEY = "__parsed_fields__" -class ModelMeta: - """ - Class used for type hinting. - Users can subclass this one for convenience but it's not required. - The only requirement is that ormar.Model has to have inner class with name Meta. - """ - - tablename: str - table: sqlalchemy.Table - metadata: sqlalchemy.MetaData - database: databases.Database - columns: List[sqlalchemy.Column] - constraints: List[ColumnCollectionConstraint] - pkname: str - model_fields: Dict[str, Union[BaseField, ForeignKeyField, ManyToManyField]] - alias_manager: AliasManager - property_fields: Set - signals: SignalEmitter - abstract: bool - requires_ref_update: bool - orders_by: List[str] - exclude_parent_fields: List[str] - extra: Extra - queryset_class: Type[QuerySet] - - def add_cached_properties(new_model: Type["Model"]) -> None: """ Sets cached properties for both pydantic and ormar models. @@ -114,7 +85,6 @@ def add_cached_properties(new_model: Type["Model"]) -> None: new_model._related_names = None new_model._through_names = None new_model._related_fields = None - new_model._pydantic_fields = {name for name in new_model.model_fields.keys()} new_model._json_fields = set() new_model._bytes_fields = set() @@ -330,7 +300,6 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 constraints=through_class.ormar_config.constraints, order_by=through_class.ormar_config.orders_by, ) - new_meta.columns = None new_meta.table = through_class.ormar_config.pkname new_meta.pkname = through_class.ormar_config.pkname new_meta.alias_manager = through_class.ormar_config.alias_manager @@ -339,7 +308,9 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 new_meta.model_fields = copy.deepcopy(through_class.ormar_config.model_fields) new_meta.property_fields = copy.deepcopy(through_class.ormar_config.property_fields) copy_name = through_class.__name__ + attrs.get("__name__", "") - copy_through = cast(Type[ormar.Model], type(copy_name, (ormar.Model,), {"ormar_config": new_meta})) + copy_through = cast( + Type[ormar.Model], type(copy_name, (ormar.Model,), {"ormar_config": new_meta}) + ) # create new table with copied columns but remove foreign keys # they will be populated later in expanding reverse relation # if hasattr(new_meta, "table"): @@ -580,7 +551,7 @@ def add_field_descriptor( def get_serializer() -> Callable: def serialize( - self, + self: "Model", value: Optional["Model"], handler: SerializerFunctionWrapHandler, ) -> Any: @@ -594,7 +565,7 @@ def serialize( except ValueError as exc: if not str(exc).startswith("Circular reference"): raise exc - return {value.ormar_config.pkname: value.pk} + return {value.ormar_config.pkname: value.pk} if value else None return serialize @@ -609,7 +580,7 @@ def __new__( # type: ignore # noqa: CCR001 __pydantic_reset_parent_namespace__: bool = True, _create_model_module: Union[str, None] = None, **kwargs, - ) -> "ModelMetaclass": + ) -> type: """ Metaclass used by ormar Models that performs configuration and build of ormar Models. @@ -698,7 +669,10 @@ def __new__( # type: ignore # noqa: CCR001 ): field_name = new_model.ormar_config.pkname new_model.model_fields[field_name] = ( - FieldInfo.from_annotated_attribute(Optional[int], None) + FieldInfo.from_annotated_attribute( + Optional[int], # type: ignore + None, + ) ) new_model.model_rebuild(force=True) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index ef30c6815..e2db737b2 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -546,7 +546,7 @@ def update_forward_refs(cls, **localns: Any) -> None: @staticmethod def _get_not_excluded_fields( - fields: Union[List, Set], include: Union[Set, Dict], exclude: Union[Set, Dict] + fields: Union[List, Set], include: Optional[Dict], exclude: Optional[Dict] ) -> List: """ Returns related field names applying on them include and exclude set. @@ -623,24 +623,39 @@ def populate_through_models( model_dict: Dict, include: Union[Set, Dict], exclude: Union[Set, Dict], - relation_map: Optional[Dict] = None, + relation_map: Dict, ) -> None: """ Populates through models with values from dict representation. :param model: model to populate through models :type model: Model - :param values: dict representation of the model - :type values: Dict + :param model_dict: dict representation of the model + :type model_dict: Dict + :param include: fields to include + :type include: Dict + :param exclude: fields to exclude + :type exclude: Dict + :param relation_map: map of relations to follow to avoid circular refs + :type relation_map: Dict :return: None :rtype: None """ - if include and isinstance(include, Set): - include = translate_list_to_dict(include) - if exclude and isinstance(exclude, Set): - exclude = translate_list_to_dict(exclude) + + include_dict = ( + translate_list_to_dict(include) + if (include and isinstance(include, Set)) + else include + ) + exclude_dict = ( + translate_list_to_dict(exclude) + if (exclude and isinstance(exclude, Set)) + else exclude + ) models_to_populate = model._get_not_excluded_fields( - fields=model.extract_through_names(), include=include, exclude=exclude + fields=model.extract_through_names(), + include=cast(Optional[Dict], include_dict), + exclude=cast(Optional[Dict], exclude_dict), ) for through_model in models_to_populate: through_field = model.ormar_config.model_fields[through_model] @@ -831,10 +846,12 @@ def dict( # type: ignore # noqa A003 for k, v in dict_instance.items() } - if include and isinstance(include, Set): - include = translate_list_to_dict(include) - if exclude and isinstance(exclude, Set): - exclude = translate_list_to_dict(exclude) + include_dict = ( + translate_list_to_dict(include) if isinstance(include, Set) else include + ) + exclude_dict = ( + translate_list_to_dict(exclude) if isinstance(exclude, Set) else exclude + ) relation_map = ( relation_map @@ -846,8 +863,8 @@ def dict( # type: ignore # noqa A003 dict_instance = self._extract_nested_models( relation_map=relation_map, dict_instance=dict_instance, - include=include, # type: ignore - exclude=exclude, # type: ignore + include=include_dict, + exclude=exclude_dict, exclude_primary_keys=exclude_primary_keys, exclude_through_models=exclude_through_models, exclude_list=exclude_list, @@ -855,7 +872,7 @@ def dict( # type: ignore # noqa A003 # include model properties as fields in dict if object.__getattribute__(self, "ormar_config").property_fields: - props = self.get_properties(include=include, exclude=exclude) + props = self.get_properties(include=include_dict, exclude=exclude_dict) if props: dict_instance.update({prop: getattr(self, prop) for prop in props}) diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index dd99a488b..4130fa318 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, Set, Type, Union +from typing import TYPE_CHECKING, Dict, List, Optional, Set, Type, Union import databases import sqlalchemy @@ -13,6 +13,17 @@ class OrmarConfig: + + if TYPE_CHECKING: + pkname: str + metadata: sqlalchemy.MetaData + database: databases.Database + tablename: str + order_by: List[str] + abstract: bool + exclude_parent_fields: List[str] + constraints: List[ColumnCollectionConstraint] + def __init__( self, metadata: Optional[sqlalchemy.MetaData] = None, @@ -25,10 +36,10 @@ def __init__( extra: Extra = Extra.forbid, constraints: Optional[List[ColumnCollectionConstraint]] = None, ) -> None: - self.pkname: str = None + self.pkname = None # type: ignore self.metadata = metadata - self.database = database - self.tablename = tablename + self.database = database # type: ignore + self.tablename = tablename # type: ignore self.orders_by = order_by or [] self.columns: List[sqlalchemy.Column] = [] self.constraints = constraints or [] diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index efc5beed3..4446d3451 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -1,6 +1,6 @@ import datetime from collections import Counter -from typing import List, Optional +from typing import Optional import databases import ormar @@ -11,10 +11,10 @@ from ormar import ModelDefinitionError from ormar.exceptions import ModelError from ormar.models.metaclass import get_constraint_copy +from ormar.relations.relation_proxy import RelationProxy from pydantic import computed_field from sqlalchemy import create_engine -from ormar.relations.relation_proxy import RelationProxy from tests.settings import DATABASE_URL metadata = sa.MetaData() @@ -200,7 +200,10 @@ class RedefinedField(DateFieldsModel): ) id: int = ormar.Integer(primary_key=True) - created_date: str = ormar.String(max_length=200, name="creation_date") # type: ignore + created_date: str = ormar.String( + max_length=200, + name="creation_date", + ) # type: ignore changed_field = RedefinedField.ormar_config.model_fields["created_date"] assert changed_field.ormar_default is None @@ -225,7 +228,7 @@ class WrongField2(DateFieldsModel): # pragma: no cover ) id: int = ormar.Integer(primary_key=True) - created_date: str = ormar.String(max_length=200) + created_date: str = ormar.String(max_length=200) # type: ignore def test_model_subclassing_non_abstract_raises_error() -> None: diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py index 65495288d..46f7b9062 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py @@ -78,15 +78,7 @@ class RedefinedField(ormar.Model, DateFieldsMixins): ) -def test_field_redefining_in_second_raises_error() -> None: - class OkField(ormar.Model, DateFieldsMixins): # pragma: no cover - ormar_config = ormar.OrmarConfig( - tablename="oks", - metadata=metadata, - database=db, - ) - - id: int = ormar.Integer(primary_key=True) +def test_field_redefining_in_second() -> None: class RedefinedField2(ormar.Model, DateFieldsMixins): ormar_config = ormar.OrmarConfig( @@ -96,7 +88,10 @@ class RedefinedField2(ormar.Model, DateFieldsMixins): ) id: int = ormar.Integer(primary_key=True) - created_date: str = ormar.String(max_length=200, name="creation_date") + created_date: str = ormar.String( + max_length=200, + name="creation_date", + ) # type: ignore assert ( RedefinedField2.ormar_config.model_fields["created_date"].ormar_default is None @@ -169,6 +164,7 @@ async def test_fields_inherited_from_mixin() -> None: assert round_date_to_seconds(sub2.created_date) == round_date_to_seconds( sub.created_date ) + assert sub2.category is not None assert sub2.category.updated_date is not None assert round_date_to_seconds( sub2.category.created_date From 8590b148df4d9fddf8a6679f9bb74245c0296452 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 31 Jan 2024 18:37:24 +0100 Subject: [PATCH 45/95] fix coverage --- ormar/fields/base.py | 10 +++++++--- ormar/fields/many_to_many.py | 5 +---- ormar/models/ormar_config.py | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ormar/fields/base.py b/ormar/fields/base.py index 7f6cee669..79a43561e 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -1,8 +1,7 @@ import warnings -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union, Sequence import sqlalchemy -from pydantic import typing from pydantic.fields import FieldInfo, _Unset import ormar # noqa I101 @@ -15,6 +14,11 @@ if TYPE_CHECKING: # pragma no cover from ormar.models import Model, NewBaseModel + from pydantic.fields import FieldInfo + + delattr(FieldInfo, "exclude") +else: + from pydantic.fields import FieldInfo class BaseField(FieldInfo): @@ -54,7 +58,7 @@ def __init__(self, **kwargs: Any) -> None: "https://collerek.github.io/ormar/fields/pydantic-fields", DeprecationWarning, ) - self.choices: typing.Sequence = kwargs.pop("choices", False) + self.choices: Sequence = kwargs.pop("choices", False) self.virtual: bool = kwargs.pop( "virtual", None diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 2739eda60..c80e4759d 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -25,10 +25,7 @@ from ormar.models import Model, T from ormar.relations.relation_proxy import RelationProxy - if sys.version_info < (3, 7): - ToType = Type["T"] - else: - ToType = Union[Type["T"], "ForwardRef"] + ToType = Union[Type["T"], "ForwardRef"] REF_PREFIX = "#/components/schemas/" diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index 4130fa318..c2a825415 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -14,7 +14,7 @@ class OrmarConfig: - if TYPE_CHECKING: + if TYPE_CHECKING: # pragma: no cover pkname: str metadata: sqlalchemy.MetaData database: databases.Database From facfbb9cddbd118d505c234a199177294b0dd4e3 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 31 Jan 2024 18:38:46 +0100 Subject: [PATCH 46/95] fix coverage --- ormar/fields/base.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ormar/fields/base.py b/ormar/fields/base.py index 79a43561e..f0329d7fa 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -14,11 +14,6 @@ if TYPE_CHECKING: # pragma no cover from ormar.models import Model, NewBaseModel - from pydantic.fields import FieldInfo - - delattr(FieldInfo, "exclude") -else: - from pydantic.fields import FieldInfo class BaseField(FieldInfo): From d38c88e2d79067b7f3541d592612e0983402944f Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 31 Jan 2024 19:18:53 +0100 Subject: [PATCH 47/95] fix type (bit dirty :shrug:) --- ormar/fields/base.py | 2 +- ormar/fields/many_to_many.py | 13 +++++++------ ormar/models/mixins/excludable_mixin.py | 2 -- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ormar/fields/base.py b/ormar/fields/base.py index f0329d7fa..80023d1a8 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -1,5 +1,5 @@ import warnings -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union, Sequence +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Type, Union import sqlalchemy from pydantic.fields import FieldInfo, _Unset diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index c80e4759d..341159b85 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -1,4 +1,3 @@ -import sys from typing import ( TYPE_CHECKING, Any, @@ -25,8 +24,6 @@ from ormar.models import Model, T from ormar.relations.relation_proxy import RelationProxy - ToType = Union[Type["T"], "ForwardRef"] - REF_PREFIX = "#/components/schemas/" @@ -88,8 +85,8 @@ def ManyToMany(to: ForwardRef, **kwargs: Any) -> "RelationProxy": # pragma: no def ManyToMany( # type: ignore - to: "ToType", - through: Optional["ToType"] = None, + to: Union[Type["T"], "ForwardRef"], + through: Optional[Union[Type["T"], "ForwardRef"]] = None, *, name: Optional[str] = None, unique: bool = False, @@ -183,7 +180,11 @@ def ManyToMany( # type: ignore return Field(**namespace) -class ManyToManyField(ForeignKeyField, ormar.QuerySetProtocol, ormar.RelationProtocol): +class ManyToManyField( # type: ignore + ForeignKeyField, + ormar.QuerySetProtocol, + ormar.RelationProtocol, +): """ Actual class returned from ManyToMany function call and stored in model_fields. """ diff --git a/ormar/models/mixins/excludable_mixin.py b/ormar/models/mixins/excludable_mixin.py index f081a2cb9..b6151ad76 100644 --- a/ormar/models/mixins/excludable_mixin.py +++ b/ormar/models/mixins/excludable_mixin.py @@ -8,7 +8,6 @@ Optional, Set, Type, - TypeVar, Union, cast, ) @@ -19,7 +18,6 @@ if TYPE_CHECKING: # pragma no cover from ormar import Model - T = TypeVar("T", bound=Model) IntStr = Union[int, str] AbstractSetIntStr = AbstractSet[IntStr] MappingIntStrAny = Mapping[IntStr, Any] From 294397546cb6871cde949b73111ae98fe68fe3f5 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 31 Jan 2024 20:01:01 +0100 Subject: [PATCH 48/95] fix some code smells --- ormar/models/helpers/validation.py | 33 ++++++++++++++++++--------- ormar/models/metaclass.py | 2 -- ormar/models/mixins/pydantic_mixin.py | 2 +- ormar/models/newbasemodel.py | 1 - 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 7dec8aaaa..73e49d839 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -139,17 +139,7 @@ def get_pydantic_example_repr(type_: Any) -> Any: :rtype: Any """ if hasattr(type_, "__origin__"): - if type_.__origin__ == Union: - values = tuple( - get_pydantic_example_repr(x) - for x in type_.__args__ - if x is not type(None) - ) - if len(values) == 1: - return values[0] - return values - if type_.__origin__ == list: - return [get_pydantic_example_repr(type_.__args__[0])] + return generate_example_for_nested_types(type_) if issubclass(type_, (numbers.Number, decimal.Decimal)): return 0 if issubclass(type_, pydantic.BaseModel): @@ -157,6 +147,27 @@ def get_pydantic_example_repr(type_: Any) -> Any: return "string" +def generate_example_for_nested_types(type_: Any) -> Any: + """ + Process nested types like Union[X, Y] or List[X] + """ + if type_.__origin__ == Union: + return generate_example_for_union(type_=type_) + if type_.__origin__ == list: + return [get_pydantic_example_repr(type_.__args__[0])] + + +def generate_example_for_union(type_: Any) -> Any: + """ + Generates a pydantic example for Union[X, Y, ...]. + Note that Optional can also be set as Union[X, None] + """ + values = tuple( + get_pydantic_example_repr(x) for x in type_.__args__ if x is not type(None) + ) + return values[0] if len(values) == 1 else values + + def overwrite_example_and_description( schema: Dict[str, Any], model: Type["Model"] ) -> None: diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 6d5f32f60..f46f8a0d1 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -288,7 +288,6 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 field.owner = base_class field.create_default_through_model() through_class = field.through - # TODO: CHECK PKNAME new_meta = ormar.OrmarConfig( tablename=through_class.ormar_config.tablename, metadata=through_class.ormar_config.metadata, @@ -655,7 +654,6 @@ def __new__( # type: ignore # noqa: CCR001 new_model = populate_meta_tablename_columns_and_pk(name, new_model) populate_meta_sqlalchemy_table_if_required(new_model.ormar_config) expand_reverse_relationships(new_model) - # TODO: iterate only related fields for field_name, field in new_model.ormar_config.model_fields.items(): register_relation_in_alias_manager(field=field) add_field_descriptor( diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index 4307aa0fd..fe3f71226 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -113,7 +113,7 @@ def _determine_pydantic_field_type( ) -> Any: field = cls.ormar_config.model_fields[name] target: Any = None - if field.is_relation and name in relation_map: # type: ignore + if field.is_relation and name in relation_map: target = field.to._convert_ormar_to_pydantic( include=cls._skip_ellipsis(include, name), exclude=cls._skip_ellipsis(exclude, name), diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index e2db737b2..913c5f0da 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -1048,7 +1048,6 @@ def _extract_model_db_fields(self) -> Dict: :return: dictionary of fields names and values. :rtype: Dict """ - # TODO: Cache this dictionary? self_fields = self._extract_own_model_fields() self_fields = { k: v From bbe1cde3f4bb2a129c664b71d93dd13d8a50fa61 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 31 Jan 2024 20:12:10 +0100 Subject: [PATCH 49/95] change pre-commit --- .pre-commit-config.yaml | 45 +++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cf3df7709..c7d4e6287 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,31 +1,18 @@ repos: - - repo: https://github.com/psf/black - rev: 22.3.0 + - repo: local hooks: - - id: black - exclude: ^(docs_src/|examples/) - - repo: https://github.com/pycqa/flake8 - rev: 3.9.2 - hooks: - - id: flake8 - exclude: ^(docs_src/|examples/|tests/) - args: [ '--max-line-length=88' ] - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.982 - hooks: - - id: mypy - exclude: ^(docs_src/|examples/) - args: [--no-strict-optional, --ignore-missing-imports] - additional_dependencies: [ - types-ujson>=0.1.1, - types-PyMySQL>=1.0.2, - types-ipaddress>=1.0.0, - types-enum34>=1.1.0, - types-cryptography>=3.3.5, - types-orjson>=3.6.0, - types-aiofiles>=0.1.9, - types-pkg-resources>=0.1.3, - types-requests>=2.25.9, - types-toml>=0.10.0, - pydantic>=1.8.2 - ] + - id: format-with-black + name: format + entry: make fmt + language: python + pass_filenames: false + - id: lint-with-ruff + name: lint + entry: make lint + language: python + pass_filenames: false + - id: type-check-with-mypy + name: type check + entry: make type_check + language: python + pass_filenames: false From d0b81544975705e7ac0fc2e8dd4a9d37b8faa63f Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 2 Feb 2024 11:47:57 +0100 Subject: [PATCH 50/95] tweak workflows --- .github/workflows/lint.yml | 25 ++++++++++++++++++------- .github/workflows/test-package.yml | 29 +++++++++++++++++++++++------ .github/workflows/type-check.yml | 22 ++++++++++++++++------ 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 28b42d7c2..53e06485a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,17 +17,28 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'collerek/ormar' steps: - uses: actions/checkout@v3 + - name: Set up Python uses: actions/setup-python@v4 with: python-version: 3.11 - - name: Install dependencies + + - name: Install Poetry + uses: snok/install-poetry@v1.3.3 + with: + version: 1.4.2 + virtualenvs-create: false + + - name: Poetry details run: | - python -m pip install poetry==1.4.2 - poetry install --extras "all" - env: - POETRY_VIRTUALENVS_CREATE: false + poetry --version + poetry config --list + + - name: Install dependencies + run: poetry install --extras "all" --no-root + - name: Format - run: python -m black . + run: make fmt + - name: Lint - run: python -m ruff . --fix + run: make lint diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 25a21cc65..4c2eaf306 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -42,31 +42,48 @@ jobs: options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: false + - name: Set up Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies + + - name: Install Poetry + uses: snok/install-poetry@v1.3.3 + with: + version: 1.4.2 + virtualenvs-create: false + + - name: Poetry details run: | - python -m pip install poetry==1.4.2 - poetry install --extras "all" - env: - POETRY_VIRTUALENVS_CREATE: false + poetry --version + poetry config --list + + - name: Install dependencies + run: poetry install --extras "all" --no-root + - name: Run mysql env: DATABASE_URL: "mysql://username:password@127.0.0.1:3306/testsuite" run: bash scripts/test.sh + - name: Run postgres env: DATABASE_URL: "postgresql://username:password@localhost:5432/testsuite" run: bash scripts/test.sh + - name: Run sqlite env: DATABASE_URL: "sqlite:///testsuite" run: bash scripts/test.sh + - name: Upload coverage uses: codecov/codecov-action@v3.1.4 + - name: Test & publish code coverage uses: paambaati/codeclimate-action@v4.0.0 if: github.event.pull_request.head.repo.full_name == 'collerek/ormar' diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml index 3a28b670c..9f4126fa4 100644 --- a/.github/workflows/type-check.yml +++ b/.github/workflows/type-check.yml @@ -17,15 +17,25 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'collerek/ormar' steps: - uses: actions/checkout@v3 + - name: Set up Python uses: actions/setup-python@v4 with: python-version: 3.11 - - name: Install dependencies + + - name: Install Poetry + uses: snok/install-poetry@v1.3.3 + with: + version: 1.4.2 + virtualenvs-create: false + + - name: Poetry details run: | - python -m pip install poetry==1.4.2 - poetry install --extras "all" - env: - POETRY_VIRTUALENVS_CREATE: false + poetry --version + poetry config --list + + - name: Install dependencies + run: poetry install --extras "all" --no-root + - name: Type check - run: python -m mypy ormar tests --ignore-missing-imports --install-types --non-interactive + run: make type_check From 7fd76e4fea500000381a20462b7c9b2488c38df2 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 2 Feb 2024 11:51:00 +0100 Subject: [PATCH 51/95] remove no root from tests --- .github/workflows/test-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 4c2eaf306..75cc4d555 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -64,7 +64,7 @@ jobs: poetry config --list - name: Install dependencies - run: poetry install --extras "all" --no-root + run: poetry install --extras "all" - name: Run mysql env: From 46b39b1fb0244a849fcce23fd53ac41b3934ca3b Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 2 Feb 2024 11:56:34 +0100 Subject: [PATCH 52/95] switch to full python path by passing sys.executable --- docs_src/test_all_docs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs_src/test_all_docs.py b/docs_src/test_all_docs.py index 4080e3434..699c00a2f 100644 --- a/docs_src/test_all_docs.py +++ b/docs_src/test_all_docs.py @@ -1,4 +1,5 @@ import subprocess +import sys from pathlib import Path import pytest @@ -15,5 +16,5 @@ @pytest.mark.parametrize("filepath", filepaths) def test_all_docs(filepath: str): - result = subprocess.run(["python", filepath]) + result = subprocess.run([sys.executable, filepath]) assert result.returncode == 0 From a8b9fcea0cde3cdc6b619961134c410d6fea8406 Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 2 Feb 2024 12:37:27 +0100 Subject: [PATCH 53/95] some small refactor in new base model, one sample test, change makefile --- .pre-commit-config.yaml | 15 +++------------ Makefile | 4 +++- ormar/models/newbasemodel.py | 17 +++++++++-------- tests/test_fastapi/test_binary_fields.py | 24 ++++++++++-------------- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c7d4e6287..c29dc6eec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,18 +1,9 @@ repos: - repo: local hooks: - - id: format-with-black + - id: pre-commit-local name: format - entry: make fmt - language: python - pass_filenames: false - - id: lint-with-ruff - name: lint - entry: make lint - language: python - pass_filenames: false - - id: type-check-with-mypy - name: type check - entry: make type_check + entry: make pre-commit language: python pass_filenames: false + diff --git a/Makefile b/Makefile index 33a086bf6..fa337fbc9 100644 --- a/Makefile +++ b/Makefile @@ -31,4 +31,6 @@ lint: poetry run python -m ruff . --fix fmt: - poetry run python -m black . \ No newline at end of file + poetry run python -m black . + +pre-commit: fmt lint type_check \ No newline at end of file diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 913c5f0da..aecf1709f 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -657,15 +657,16 @@ def populate_through_models( include=cast(Optional[Dict], include_dict), exclude=cast(Optional[Dict], exclude_dict), ) - for through_model in models_to_populate: - through_field = model.ormar_config.model_fields[through_model] - if through_field.related_name in relation_map: - continue - through_instance = getattr(model, through_model) + through_fields_to_populate = [ + model.ormar_config.model_fields[through_model] + for through_model in models_to_populate + if model.ormar_config.model_fields[through_model].related_name + not in relation_map + ] + for through_field in through_fields_to_populate: + through_instance = getattr(model, through_field.name) if through_instance: - model_dict[through_model] = through_instance.dict() - # else: - # model_dict[through_model] = None + model_dict[through_field.name] = through_instance.dict() @classmethod def _skip_ellipsis( diff --git a/tests/test_fastapi/test_binary_fields.py b/tests/test_fastapi/test_binary_fields.py index d8436f173..cd387f2a2 100644 --- a/tests/test_fastapi/test_binary_fields.py +++ b/tests/test_fastapi/test_binary_fields.py @@ -1,7 +1,8 @@ import base64 import uuid +from contextlib import asynccontextmanager from enum import Enum -from typing import List +from typing import AsyncIterator, List import databases import ormar @@ -13,27 +14,22 @@ from tests.settings import DATABASE_URL -app = FastAPI() - database = databases.Database(DATABASE_URL, force_rollback=True) metadata = sqlalchemy.MetaData() -app.state.database = database headers = {"content-type": "application/json"} -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() +@asynccontextmanager +async def lifespan(app: FastAPI) -> AsyncIterator[None]: + if not database.is_connected: + await database.connect() + yield + if database.is_connected: + await database.disconnect() -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() +app = FastAPI(lifespan=lifespan) blob3 = b"\xc3\x83\x28" From e7a5a41c31b3c19957cd5b903ad99b4e26f100cd Mon Sep 17 00:00:00 2001 From: collerek Date: Fri, 2 Feb 2024 16:55:34 +0100 Subject: [PATCH 54/95] small refactors to reduce complexity of methods --- ormar/fields/base.py | 23 ++++++++++--- ormar/fields/parsers.py | 2 +- ormar/fields/sqlalchemy_encrypted.py | 49 ++++++++++++++++------------ ormar/models/newbasemodel.py | 1 - 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/ormar/fields/base.py b/ormar/fields/base.py index 80023d1a8..23e670a14 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -196,11 +196,26 @@ def get_default( default = ( self.ormar_default if self.ormar_default is not None - else (self.server_default if use_server else None) + else self._get_default_server_value(use_server=use_server) ) - if callable(default) and call_default_factory: # pragma: no cover - default = default() - return default + return self._get_default_callable_value( + default=default, + call_default_factory=call_default_factory, + ) + + def _get_default_server_value(self, use_server: bool) -> Any: + """ + Return default value for a server side if use_server is True + """ + return self.server_default if use_server else None + + @staticmethod + def _get_default_callable_value(default: Any, call_default_factory: bool) -> Any: + """ + Return default factory value if call_default_factory is True + and default is a callable. + """ + return default() if (callable(default) and call_default_factory) else default def has_default(self, use_server: bool = True) -> bool: """ diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index 0bde4e56f..4e29686e2 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -84,7 +84,7 @@ def re_dump_value(value: str) -> Union[str, bytes]: } -DECODERS_MAP = { +DECODERS_MAP: Dict[type, Callable] = { bool: parse_bool, datetime.datetime: SchemaValidator(core_schema.datetime_schema()).validate_python, datetime.date: SchemaValidator(core_schema.date_schema()).validate_python, diff --git a/ormar/fields/sqlalchemy_encrypted.py b/ormar/fields/sqlalchemy_encrypted.py index dcfb3eeaa..1ad13f95e 100644 --- a/ormar/fields/sqlalchemy_encrypted.py +++ b/ormar/fields/sqlalchemy_encrypted.py @@ -2,7 +2,7 @@ import abc import base64 from enum import Enum -from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Type, Union import sqlalchemy.types as types from sqlalchemy.engine import Dialect @@ -164,15 +164,14 @@ def process_bind_param(self, value: Any, dialect: Dialect) -> Optional[str]: try: value = self._underlying_type.process_bind_param(value, dialect) except AttributeError: - encoder = ormar.SQL_ENCODERS_MAP.get(self.type_, None) - if encoder: - if self.type_ in ADDITIONAL_PARAMETERS_MAP: - additional_parameter = getattr( - self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_] - ) - value = encoder(value, additional_parameter) - else: - value = encoder(value) # type: ignore + encoder, additional_parameter = self._get_coder_type_and_params( + coders=ormar.SQL_ENCODERS_MAP + ) + if encoder is not None: + params = [value] + ( + [additional_parameter] if additional_parameter else [] + ) + value = encoder(*params) encrypted_value = self.backend.encrypt(value) return encrypted_value @@ -185,16 +184,24 @@ def process_result_value(self, value: Any, dialect: Dialect) -> Any: try: return self._underlying_type.process_result_value(decrypted_value, dialect) except AttributeError: - decoder = ormar.DECODERS_MAP.get(self.type_, None) - if decoder: - if self.type_ in ADDITIONAL_PARAMETERS_MAP: - additional_parameter = getattr( - self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_] - ) - return decoder( - decrypted_value, - additional_parameter, - ) # type: ignore - return decoder(decrypted_value) # type: ignore + decoder, additional_parameter = self._get_coder_type_and_params( + coders=ormar.DECODERS_MAP + ) + if decoder is not None: + params = [decrypted_value] + ( + [additional_parameter] if additional_parameter else [] + ) + return decoder(*params) # type: ignore return self._field_type.__type__(decrypted_value) # type: ignore + + def _get_coder_type_and_params( + self, coders: Dict[type, Callable] + ) -> Tuple[Optional[Callable], Optional[str]]: + coder = coders.get(self.type_, None) + additional_parameter: Optional[str] = None + if self.type_ in ADDITIONAL_PARAMETERS_MAP: + additional_parameter = getattr( + self._field_type, ADDITIONAL_PARAMETERS_MAP[self.type_] + ) + return coder, additional_parameter diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index aecf1709f..504bb83be 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -185,7 +185,6 @@ def __getattr__(self, item: str) -> Any: :return: Any :rtype: Any """ - # TODO: To many fields land here - descriptors problem? # TODO: Check __pydantic_extra__ if item == "__pydantic_extra__": return None From c65fcc9a57bea27d79d8a423d4805ca3efdce099 Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 5 Feb 2024 17:24:10 +0100 Subject: [PATCH 55/95] temp add tests for prs against pydantic_v2 --- .github/workflows/lint.yml | 2 +- .github/workflows/test-package.yml | 2 +- .github/workflows/test_docs.yml | 2 +- .github/workflows/type-check.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 53e06485a..ae6f2a3ad 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,7 +8,7 @@ on: branches-ignore: - 'gh-pages' pull_request: - branches: [ master ] + branches: [ master, pydantic_v2 ] jobs: lint: diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 75cc4d555..8f1d7bdc1 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -8,7 +8,7 @@ on: branches-ignore: - 'gh-pages' pull_request: - branches: [ master ] + branches: [ master, pydantic_v2 ] jobs: tests: diff --git a/.github/workflows/test_docs.yml b/.github/workflows/test_docs.yml index 7124e3af7..eb5dd4f21 100644 --- a/.github/workflows/test_docs.yml +++ b/.github/workflows/test_docs.yml @@ -8,7 +8,7 @@ on: branches-ignore: - 'gh-pages' pull_request: - branches: [ master ] + branches: [ master, pydantic_v2 ] jobs: tests_docs: diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml index 9f4126fa4..79bf6aa76 100644 --- a/.github/workflows/type-check.yml +++ b/.github/workflows/type-check.yml @@ -8,7 +8,7 @@ on: branches-ignore: - 'gh-pages' pull_request: - branches: [ master ] + branches: [ master, pydantic_v2 ] jobs: lint: From 5d6540ed11a9b87ae7fd67be327be13b9901243e Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 5 Feb 2024 20:57:25 +0100 Subject: [PATCH 56/95] remove all references to __fields__ --- ormar/models/quick_access_views.py | 2 +- .../test_excluding_parent_fields_inheritance.py | 4 ++-- .../test_inheritance_with_default.py | 8 ++++---- .../test_pydantic_fields_order.py | 2 +- tests/test_model_definition/test_model_definition.py | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ormar/models/quick_access_views.py b/ormar/models/quick_access_views.py index 28f19fea1..a44c08f08 100644 --- a/ormar/models/quick_access_views.py +++ b/ormar/models/quick_access_views.py @@ -12,7 +12,7 @@ "__config__", "__custom_root_type__", "__dict__", - "__fields__", + "model_fields", "__fields_set__", "__json_encoder__", "__pk_only__", diff --git a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py index 02bc2d5bf..e7ac3c29e 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py +++ b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py @@ -96,7 +96,7 @@ def create_test_database(): def test_model_definition(): model_fields = Category.ormar_config.model_fields sqlalchemy_columns = Category.ormar_config.table.c - pydantic_columns = Category.__fields__ + pydantic_columns = Category.model_fields assert "updated_by" not in model_fields assert "updated_by" not in sqlalchemy_columns assert "updated_by" not in pydantic_columns @@ -106,7 +106,7 @@ def test_model_definition(): assert "updated_by" not in Gun.ormar_config.model_fields assert "updated_by" not in Gun.ormar_config.table.c - assert "updated_by" not in Gun.__fields__ + assert "updated_by" not in Gun.model_fields @pytest.mark.asyncio diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py index c1b405514..27db40dee 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py @@ -45,15 +45,15 @@ def create_test_database(): def test_model_structure(): - assert "id" in BaseModel.__fields__ + assert "id" in BaseModel.model_fields assert "id" in BaseModel.ormar_config.model_fields assert BaseModel.ormar_config.model_fields["id"].has_default() - assert BaseModel.__fields__["id"].default_factory is not None + assert BaseModel.model_fields["id"].default_factory is not None - assert "id" in Member.__fields__ + assert "id" in Member.model_fields assert "id" in Member.ormar_config.model_fields assert Member.ormar_config.model_fields["id"].has_default() - assert Member.__fields__["id"].default_factory is not None + assert Member.model_fields["id"].default_factory is not None @pytest.mark.asyncio diff --git a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py index fe57cdec1..b53aa5676 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py +++ b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py @@ -40,4 +40,4 @@ def create_test_database(): def test_model_field_order(): TestCreate = NewTestModel.get_pydantic(exclude={"a"}) - assert list(TestCreate.__fields__.keys()) == ["b", "c", "d", "e", "f"] + assert list(TestCreate.model_fields.keys()) == ["b", "c", "d", "e", "f"] diff --git a/tests/test_model_definition/test_model_definition.py b/tests/test_model_definition/test_model_definition.py index 57fd521c5..f5021f04c 100644 --- a/tests/test_model_definition/test_model_definition.py +++ b/tests/test_model_definition/test_model_definition.py @@ -160,7 +160,7 @@ def test_primary_key_access_and_setting(example): def test_pydantic_model_is_created(example): assert issubclass(example.__class__, pydantic.BaseModel) - assert all([field in example.__fields__ for field in fields_to_check]) + assert all([field in example.model_fields for field in fields_to_check]) assert example.test == 1 From 8e93de65de4d282deff6150334b886093af57856 Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 5 Feb 2024 21:18:38 +0100 Subject: [PATCH 57/95] remove all references to construct, deprecate the method and update model_construct to be in line with pydantic --- ormar/models/newbasemodel.py | 42 ++++++++++++++++- ormar/warnings.py | 47 +++++++++++++++++++ pyproject.toml | 2 +- .../test_model_construct.py | 14 ++++-- 4 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 ormar/warnings.py diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 504bb83be..320987481 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -1,5 +1,6 @@ import base64 import sys +import warnings from typing import ( TYPE_CHECKING, AbstractSet, @@ -19,6 +20,7 @@ import pydantic import sqlalchemy +import typing_extensions import ormar # noqa I100 from ormar.exceptions import ModelError, ModelPersistenceError @@ -38,6 +40,7 @@ from ormar.relations.alias_manager import AliasManager from ormar.relations.relation import Relation from ormar.relations.relation_manager import RelationsManager +from ormar.warnings import OrmarDeprecatedSince020 if TYPE_CHECKING: # pragma no cover from ormar.models import Model, OrmarConfig @@ -911,7 +914,21 @@ def json( # type: ignore # noqa A003 return self.__pydantic_serializer__.to_json(data).decode() @classmethod + @typing_extensions.deprecated( + "The `construct` method is deprecated; use `model_construct` instead.", + category=OrmarDeprecatedSince020, + ) def construct( + cls: Type["T"], _fields_set: set[str] | None = None, **values: Any + ) -> "T": + warnings.warn( + "The `construct` method is deprecated; use `model_construct` instead.", + DeprecationWarning, + ) + return cls.model_construct(_fields_set=_fields_set, **values) + + @classmethod + def model_construct( cls: Type["T"], _fields_set: Optional["SetStr"] = None, **values: Any ) -> "T": own_values = { @@ -925,12 +942,33 @@ def construct( elif not field.is_required(): fields_values[name] = field.get_default() fields_values.update(own_values) + + if _fields_set is None: + _fields_set = set(values.keys()) + + _extra: dict[str, Any] | None = None + if cls.model_config.get("extra") == "allow": + _extra = {} + for k, v in values.items(): + _extra[k] = v + else: + fields_values.update(values) object.__setattr__(model, "__dict__", fields_values) model._initialize_internal_attributes() cls._construct_relations(model=model, values=values) - if _fields_set is None: - _fields_set = set(values.keys()) object.__setattr__(model, "__pydantic_fields_set__", _fields_set) + if not cls.__pydantic_root_model__: + object.__setattr__(model, "__pydantic_extra__", _extra) + + if cls.__pydantic_post_init__: + model.model_post_init(None) + elif not cls.__pydantic_root_model__: + # Note: if there are any private attributes, + # cls.__pydantic_post_init__ would exist + # Since it doesn't, that means that `__pydantic_private__` + # should be set to None + object.__setattr__(model, "__pydantic_private__", None) + return model @classmethod diff --git a/ormar/warnings.py b/ormar/warnings.py new file mode 100644 index 000000000..74d617c06 --- /dev/null +++ b/ormar/warnings.py @@ -0,0 +1,47 @@ +class OrmarDeprecationWarning(DeprecationWarning): + """A Pydantic specific deprecation warning. + + This warning is raised when using deprecated functionality in Ormar. + It provides information on when the deprecation was introduced and + the expected version in which the corresponding functionality will be removed. + + Attributes: + message: Description of the warning + since: Ormar version in what the deprecation was introduced + expected_removal: Ormar version in what the functionality will be removed + """ + + message: str + since: tuple[int, int] + expected_removal: tuple[int, int] + + def __init__( + self, + message: str, + *args: object, + since: tuple[int, int], + expected_removal: tuple[int, int] | None = None, + ) -> None: + super().__init__(message, *args) + self.message = message.rstrip(".") + self.since = since + self.expected_removal = ( + expected_removal if expected_removal is not None else (since[0] + 1, 0) + ) + + def __str__(self) -> str: + message = ( + f"{self.message}. Deprecated in Ormar V{self.since[0]}.{self.since[1]}" + f" to be removed in V{self.expected_removal[0]}.{self.expected_removal[1]}." + ) + if self.since == (0, 20): + message += " See Ormar V0.20 Migration Guide at https://collerek.github.io/ormar/migration-to-v0.20/" + return message + + +class OrmarDeprecatedSince020(OrmarDeprecationWarning): + """A specific `OrmarDeprecationWarning` subclass defining + functionality deprecated since Ormar 0.20.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(0, 20), expected_removal=(0, 30)) diff --git a/pyproject.toml b/pyproject.toml index 50e52d876..ff30c9002 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "ormar" [tool.poetry] name = "ormar" -version = "0.12.2" +version = "0.20.0" description = "An async ORM with fastapi in mind and pydantic validation." authors = ["Radosław Drążkiewicz "] license = "MIT" diff --git a/tests/test_model_definition/test_model_construct.py b/tests/test_model_definition/test_model_construct.py index f34bd3f45..628e8588a 100644 --- a/tests/test_model_definition/test_model_construct.py +++ b/tests/test_model_definition/test_model_construct.py @@ -70,7 +70,9 @@ async def test_construct_with_empty_relation(): async with database.transaction(force_rollback=True): await HQ.objects.create(name="Main") comp = Company(name="Banzai", hq=None, founded=1988) - comp2 = Company.construct(**dict(name="Banzai", hq=None, founded=1988)) + comp2 = Company.model_construct( + **dict(name="Banzai", hq=None, founded=1988) + ) assert comp.dict() == comp2.dict() @@ -80,10 +82,12 @@ async def test_init_and_construct_has_same_effect(): async with database.transaction(force_rollback=True): hq = await HQ.objects.create(name="Main") comp = Company(name="Banzai", hq=hq, founded=1988) - comp2 = Company.construct(**dict(name="Banzai", hq=hq, founded=1988)) + comp2 = Company.model_construct(**dict(name="Banzai", hq=hq, founded=1988)) assert comp.dict() == comp2.dict() - comp3 = Company.construct(**dict(name="Banzai", hq=hq.dict(), founded=1988)) + comp3 = Company.model_construct( + **dict(name="Banzai", hq=hq.dict(), founded=1988) + ) assert comp.dict() == comp3.dict() @@ -94,8 +98,8 @@ async def test_init_and_construct_has_same_effect_with_m2m(): n1 = await NickNames(name="test").save() n2 = await NickNames(name="test2").save() hq = HQ(name="Main", nicks=[n1, n2]) - hq2 = HQ.construct(**dict(name="Main", nicks=[n1, n2])) + hq2 = HQ.model_construct(**dict(name="Main", nicks=[n1, n2])) assert hq.dict() == hq2.dict() - hq3 = HQ.construct(**dict(name="Main", nicks=[n1.dict(), n2.dict()])) + hq3 = HQ.model_construct(**dict(name="Main", nicks=[n1.dict(), n2.dict()])) assert hq.dict() == hq3.dict() From 68dbcf645d658d600dba2d49b3e9c5c10eadb854 Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 5 Feb 2024 21:33:27 +0100 Subject: [PATCH 58/95] deprecate dict and add model_dump, todo switch to model_dict in calls --- ormar/models/newbasemodel.py | 52 +++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 320987481..c4e765ee0 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -7,6 +7,7 @@ Any, Dict, List, + Literal, Mapping, MutableSequence, Optional, @@ -783,6 +784,10 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 dict_instance[field] = None return dict_instance + @typing_extensions.deprecated( + "The `dict` method is deprecated; use `model_dump` instead.", + category=OrmarDeprecatedSince020, + ) def dict( # type: ignore # noqa A003 self, *, @@ -796,6 +801,40 @@ def dict( # type: ignore # noqa A003 exclude_through_models: bool = False, exclude_list: bool = False, relation_map: Optional[Dict] = None, + ) -> "DictStrAny": # noqa: A003' + warnings.warn( + "The `dict` method is deprecated; use `model_dump` instead.", + DeprecationWarning, + ) + return self.model_dump( + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_primary_keys=exclude_primary_keys, + exclude_through_models=exclude_through_models, + exclude_list=exclude_list, + relation_map=relation_map, + ) + + def model_dump( # type: ignore # noqa A003 + self, + *, + mode: Literal["json", "python"] | str = "python", + include: Union[Set, Dict, None] = None, + exclude: Union[Set, Dict, None] = None, + by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_primary_keys: bool = False, + exclude_through_models: bool = False, + exclude_list: bool = False, + relation_map: Optional[Dict] = None, + round_trip: bool = False, + warnings: bool = True, ) -> "DictStrAny": # noqa: A003' """ @@ -824,8 +863,16 @@ def dict( # type: ignore # noqa A003 :type exclude_none: bool :param exclude_list: flag to exclude lists of nested values models from dict :type exclude_list: bool - :param relation_map: map of the relations to follow to avoid circural deps + :param relation_map: map of the relations to follow to avoid circular deps :type relation_map: Dict + :param mode: The mode in which `to_python` should run. + If mode is 'json', the dictionary will only contain JSON serializable types. + If mode is 'python', the dictionary may contain any Python objects. + :type mode: str + :param round_trip: flag to enable serialization round-trip support + :type round_trip: bool + :param warnings: flag to log warnings for invalid fields + :type warnings: bool :return: :rtype: """ @@ -836,12 +883,15 @@ def dict( # type: ignore # noqa A003 exclude_through_models=exclude_through_models, ) dict_instance = super().model_dump( + mode=mode, include=include, exclude=pydantic_exclude, by_alias=by_alias, exclude_defaults=exclude_defaults, exclude_unset=exclude_unset, exclude_none=exclude_none, + round_trip=round_trip, + warnings=warnings, ) dict_instance = { From 644de372045271272b71197c71e15991b4eeaa13 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 08:50:40 +0100 Subject: [PATCH 59/95] fix tests --- ormar/models/helpers/relations.py | 2 +- ormar/models/newbasemodel.py | 8 ++++---- ormar/warnings.py | 14 +++++++++----- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index cfc2d2d99..5c94ecd04 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -168,7 +168,7 @@ def serialize( try: return handler(children) except ValueError as exc: - if not str(exc).startswith("Circular reference"): + if not str(exc).startswith("Circular reference"): # pragma: no cover raise exc result = [] diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index c4e765ee0..7e79fa645 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -801,7 +801,7 @@ def dict( # type: ignore # noqa A003 exclude_through_models: bool = False, exclude_list: bool = False, relation_map: Optional[Dict] = None, - ) -> "DictStrAny": # noqa: A003' + ) -> "DictStrAny": # noqa: A003 # pragma: no cover warnings.warn( "The `dict` method is deprecated; use `model_dump` instead.", DeprecationWarning, @@ -970,7 +970,7 @@ def json( # type: ignore # noqa A003 ) def construct( cls: Type["T"], _fields_set: set[str] | None = None, **values: Any - ) -> "T": + ) -> "T": # pragma: no cover warnings.warn( "The `construct` method is deprecated; use `model_construct` instead.", DeprecationWarning, @@ -997,7 +997,7 @@ def model_construct( _fields_set = set(values.keys()) _extra: dict[str, Any] | None = None - if cls.model_config.get("extra") == "allow": + if cls.model_config.get("extra") == "allow": # pragma: no cover _extra = {} for k, v in values.items(): _extra[k] = v @@ -1010,7 +1010,7 @@ def model_construct( if not cls.__pydantic_root_model__: object.__setattr__(model, "__pydantic_extra__", _extra) - if cls.__pydantic_post_init__: + if cls.__pydantic_post_init__: # pragma: no cover model.model_post_init(None) elif not cls.__pydantic_root_model__: # Note: if there are any private attributes, diff --git a/ormar/warnings.py b/ormar/warnings.py index 74d617c06..4c14e80ad 100644 --- a/ormar/warnings.py +++ b/ormar/warnings.py @@ -1,3 +1,7 @@ +# Adopted from pydantic +from typing import Optional, Tuple + + class OrmarDeprecationWarning(DeprecationWarning): """A Pydantic specific deprecation warning. @@ -12,15 +16,15 @@ class OrmarDeprecationWarning(DeprecationWarning): """ message: str - since: tuple[int, int] - expected_removal: tuple[int, int] + since: Tuple[int, int] + expected_removal: Tuple[int, int] def __init__( self, message: str, *args: object, - since: tuple[int, int], - expected_removal: tuple[int, int] | None = None, + since: Tuple[int, int], + expected_removal: Optional[Tuple[int, int]] = None, ) -> None: super().__init__(message, *args) self.message = message.rstrip(".") @@ -29,7 +33,7 @@ def __init__( expected_removal if expected_removal is not None else (since[0] + 1, 0) ) - def __str__(self) -> str: + def __str__(self) -> str: # pragma: no cover message = ( f"{self.message}. Deprecated in Ormar V{self.since[0]}.{self.since[1]}" f" to be removed in V{self.expected_removal[0]}.{self.expected_removal[1]}." From 606f0680f0700600f96fead40170a8a0888394d2 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 08:55:44 +0100 Subject: [PATCH 60/95] change to union --- ormar/models/newbasemodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 7e79fa645..59612f816 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -822,7 +822,7 @@ def dict( # type: ignore # noqa A003 def model_dump( # type: ignore # noqa A003 self, *, - mode: Literal["json", "python"] | str = "python", + mode: Union[Literal["json", "python"], str] = "python", include: Union[Set, Dict, None] = None, exclude: Union[Set, Dict, None] = None, by_alias: bool = False, From 08d8b026d8184d8aaf37b0826af54edd0b006000 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 09:00:22 +0100 Subject: [PATCH 61/95] change to union --- ormar/models/newbasemodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 59612f816..37f474881 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -969,7 +969,7 @@ def json( # type: ignore # noqa A003 category=OrmarDeprecatedSince020, ) def construct( - cls: Type["T"], _fields_set: set[str] | None = None, **values: Any + cls: Type["T"], _fields_set: Union[Set[str], None] = None, **values: Any ) -> "T": # pragma: no cover warnings.warn( "The `construct` method is deprecated; use `model_construct` instead.", From 8ff428bb9ecd3220065c7db801fec8aec789ca16 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 15:58:44 +0100 Subject: [PATCH 62/95] change to model_dump and model_dump_json from dict and json deprecated methods, deprecate them in ormar too --- docs/fastapi/index.md | 8 ++-- docs/fastapi/requests.md | 10 ++--- docs/fastapi/response.md | 12 ++--- docs/models/index.md | 8 ++-- docs/models/methods.md | 38 ++++++++-------- docs/relations/foreign-key.md | 8 ++-- docs/relations/many-to-many.md | 6 +-- docs/releases.md | 8 ++-- docs/signals.md | 6 +-- ormar/models/mixins/save_mixin.py | 2 +- ormar/models/model.py | 2 +- ormar/models/newbasemodel.py | 45 ++++++++++++++++--- ormar/queryset/queryset.py | 4 +- .../test_more_same_table_joins.py | 6 +-- tests/test_deferred/test_same_table_joins.py | 2 +- .../test_dumping_model_to_dict.py | 4 +- .../test_excluding_subset_of_columns.py | 2 +- .../test_pydantic_dict_params.py | 6 +-- .../test_excludes_with_get_pydantic.py | 12 ++--- tests/test_fastapi/test_excluding_fields.py | 8 ++-- tests/test_fastapi/test_fastapi_docs.py | 6 ++- .../test_inheritance_concrete_fastapi.py | 25 +++++++---- .../test_inheritance_mixins_fastapi.py | 2 +- tests/test_fastapi/test_json_field_fastapi.py | 6 +-- .../test_more_reallife_fastapi.py | 6 +-- tests/test_fastapi/test_nested_saving.py | 6 +-- tests/test_fastapi/test_recursion_error.py | 2 +- tests/test_fastapi/test_wekref_exclusion.py | 2 +- tests/test_model_definition/test_aliases.py | 2 +- .../test_model_construct.py | 4 +- tests/test_model_definition/test_models.py | 2 +- .../test_model_definition/test_properties.py | 4 +- .../test_pydantic_only_fields.py | 4 +- .../test_model_definition/test_save_status.py | 2 +- .../test_save_related_uuid.py | 2 +- tests/test_relations/test_skipping_reverse.py | 4 +- tests/test_signals/test_signals.py | 2 +- 37 files changed, 160 insertions(+), 118 deletions(-) diff --git a/docs/fastapi/index.md b/docs/fastapi/index.md index adad78201..fe5b8abd3 100644 --- a/docs/fastapi/index.md +++ b/docs/fastapi/index.md @@ -122,7 +122,7 @@ async def create_category(category: Category): @app.put("/items/{item_id}") async def get_item(item_id: int, item: Item): item_db = await Item.objects.get(pk=item_id) - return await item_db.update(**item.dict()) + return await item_db.update(**item.model_dump()) @app.delete("/items/{item_id}") @@ -197,14 +197,14 @@ def test_all_endpoints(): assert items[0] == item item.name = "New name" - response = client.put(f"/items/{item.pk}", json=item.dict()) - assert response.json() == item.dict() + response = client.put(f"/items/{item.pk}", json=item.model_dump()) + assert response.json() == item.model_dump() response = client.get("/items/") items = [Item(**item) for item in response.json()] assert items[0].name == "New name" - response = client.delete(f"/items/{item.pk}", json=item.dict()) + response = client.delete(f"/items/{item.pk}", json=item.model_dump()) assert response.json().get("deleted_rows", "__UNDEFINED__") != "__UNDEFINED__" response = client.get("/items/") items = response.json() diff --git a/docs/fastapi/requests.md b/docs/fastapi/requests.md index 7183465b4..426373c6c 100644 --- a/docs/fastapi/requests.md +++ b/docs/fastapi/requests.md @@ -66,14 +66,14 @@ RequestUser = User.get_pydantic(exclude={"password": ..., "category": {"priority @app.post("/users3/", response_model=User) # here you can also use both ormar/pydantic async def create_user3(user: RequestUser): # use the generated model here # note how now user is pydantic and not ormar Model so you need to convert - return await User(**user.dict()).save() + return await User(**user.model_dump()).save() ``` !!!Note To see more examples and read more visit [get_pydantic](../models/methods.md#get_pydantic) part of the documentation. !!!Warning - The `get_pydantic` method generates all models in a tree of nested models according to an algorithm that allows to avoid loops in models (same algorithm that is used in `dict()`, `select_all()` etc.) + The `get_pydantic` method generates all models in a tree of nested models according to an algorithm that allows to avoid loops in models (same algorithm that is used in `model_dump()`, `select_all()` etc.) That means that nested models won't have reference to parent model (by default ormar relation is biderectional). @@ -94,7 +94,7 @@ RequestUser = User.get_pydantic(exclude={"password": ..., "category": {"priority @app.post("/users3/", response_model=User) async def create_user3(user: RequestUser): # type: ignore # note how now user is not ormar Model so you need to convert - return await User(**user.dict()).save() + return await User(**user.model_dump()).save() ``` The second one is a little bit more hacky and utilizes a way in which fastapi extract function parameters. @@ -105,7 +105,7 @@ You can overwrite the `__annotations__` entry for given param. RequestUser = User.get_pydantic(exclude={"password": ..., "category": {"priority"}}) # do not use the app decorator async def create_user3(user: User): # use ormar model here - return await User(**user.dict()).save() + return await User(**user.model_dump()).save() # overwrite the function annotations entry for user param with generated model create_user3.__annotations__["user"] = RequestUser # manually call app functions (app.get, app.post etc.) and pass your function reference @@ -139,5 +139,5 @@ class UserCreate(pydantic.BaseModel): async def create_user3(user: UserCreate): # use pydantic model here # note how now request param is a pydantic model and not the ormar one # so you need to parse/convert it to ormar before you can use database - return await User(**user.dict()).save() + return await User(**user.model_dump()).save() ``` \ No newline at end of file diff --git a/docs/fastapi/response.md b/docs/fastapi/response.md index 0cd7a1fea..8b1349922 100644 --- a/docs/fastapi/response.md +++ b/docs/fastapi/response.md @@ -153,7 +153,7 @@ In example `response_model_exclude={"category__priority", "category__other_field Note that apart from `response_model_exclude` parameter `fastapi` supports also other parameters inherited from `pydantic`. All of them works also with ormar, but can have some nuances so best to read [dict](../models/methods.md#dict) part of the documentation. -### Exclude in `Model.dict()` +### Exclude in `Model.model_dump()` Alternatively you can just return a dict from `ormar.Model` and use . @@ -166,14 +166,14 @@ Like this you can also set exclude/include as dict and exclude fields on nested @app.post("/users2/", response_model=User) async def create_user2(user: User): user = await user.save() - return user.dict(exclude={'password'}) - # could be also something like return user.dict(exclude={'category': {'priority'}}) to exclude category priority + return user.model_dump(exclude={'password'}) + # could be also something like return user.model_dump(exclude={'category': {'priority'}}) to exclude category priority ``` !!!Note Note that above example will nullify the password field even if you pass it in request, but the **field will be still there** as it's part of the response schema, the value will be set to `None`. -If you want to fully exclude the field with this approach simply don't use `response_model` and exclude in Model's dict() +If you want to fully exclude the field with this approach simply don't use `response_model` and exclude in Model's model_dump() Alternatively you can just return a dict from ormar model. Like this you can also set exclude/include as dict and exclude fields on nested models. @@ -187,7 +187,7 @@ So if you skip `response_model` altogether you can do something like this: @app.post("/users4/") # note no response_model async def create_user4(user: User): user = await user.save() - return user.dict(exclude={'last_name'}) + return user.model_dump(exclude={'last_name'}) ``` !!!Note @@ -213,7 +213,7 @@ async def create_user3(user: User): To see more examples and read more visit [get_pydantic](../models/methods.md#get_pydantic) part of the documentation. !!!Warning - The `get_pydantic` method generates all models in a tree of nested models according to an algorithm that allows to avoid loops in models (same algorithm that is used in `dict()`, `select_all()` etc.) + The `get_pydantic` method generates all models in a tree of nested models according to an algorithm that allows to avoid loops in models (same algorithm that is used in `model_dump()`, `select_all()` etc.) That means that nested models won't have reference to parent model (by default ormar relation is biderectional). diff --git a/docs/models/index.md b/docs/models/index.md index 3f1437575..ce6ae9843 100644 --- a/docs/models/index.md +++ b/docs/models/index.md @@ -45,7 +45,7 @@ Note that if you need a normal pydantic field in your model (used to store value field with parameter `pydantic_only=True`. Fields created like this are added to the `pydantic` model fields -> so are subject to validation according to `Field` type, -also appear in `dict()` and `json()` result. +also appear in `model_dump()` and `json()` result. The difference is that **those fields are not saved in the database**. So they won't be included in underlying sqlalchemy `columns`, or `table` variables (check [Internals][Internals] section below to see how you can access those if you need). @@ -72,7 +72,7 @@ If you combine `pydantic_only=True` field with `default` parameter and do not pa Since it can be a function you can set `default=datetime.datetime.now` and get current timestamp each time you call an endpoint etc. !!!note - Note that both `pydantic_only` and `property_field` decorated field can be included/excluded in both `dict()` and `fastapi` + Note that both `pydantic_only` and `property_field` decorated field can be included/excluded in both `model_dump()` and `fastapi` response with `include`/`exclude` and `response_model_include`/`response_model_exclude` accordingly. ```python @@ -169,11 +169,11 @@ But it's so common that `ormar` has you covered. You can "materialize" a `proper ``` Note that `property_field` decorated methods do not go through verification (but that might change in future) and are only available -in the response from `fastapi` and `dict()` and `json()` methods. You cannot pass a value for this field in the request +in the response from `fastapi` and `model_dump()` and `json()` methods. You cannot pass a value for this field in the request (or rather you can but it will be discarded by ormar so really no point but no Exception will be raised). !!!note - Note that both `pydantic_only` and `property_field` decorated field can be included/excluded in both `dict()` and `fastapi` + Note that both `pydantic_only` and `property_field` decorated field can be included/excluded in both `model_dump()` and `fastapi` response with `include`/`exclude` and `response_model_include`/`response_model_exclude` accordingly. !!!tip diff --git a/docs/models/methods.md b/docs/models/methods.md index 7cbecea18..fc5a2e968 100644 --- a/docs/models/methods.md +++ b/docs/models/methods.md @@ -13,7 +13,7 @@ Available methods are described below. ## `pydantic` methods Note that each `ormar.Model` is also a `pydantic.BaseModel`, so all `pydantic` methods are also available on a model, -especially `dict()` and `json()` methods that can also accept `exclude`, `include` and other parameters. +especially `model_dump()` and `json()` methods that can also accept `exclude`, `include` and other parameters. To read more check [pydantic][pydantic] documentation @@ -118,17 +118,17 @@ class Item(ormar.Model): categories: List[Category] = ormar.ManyToMany(Category) category = Category(name="Test 2") -assert category.dict() == {'id': None, 'items': [], 'name': 'Test 2', +assert category.model_dump() == {'id': None, 'items': [], 'name': 'Test 2', 'visibility': True} -assert category.dict(exclude_unset=True) == {'items': [], 'name': 'Test 2'} +assert category.model_dump(exclude_unset=True) == {'items': [], 'name': 'Test 2'} await category.save() category2 = await Category.objects.get() -assert category2.dict() == {'id': 1, 'items': [], 'name': 'Test 2', +assert category2.model_dump() == {'id': 1, 'items': [], 'name': 'Test 2', 'visibility': True} # NOTE how after loading from db all fields are set explicitly # as this is what happens when you populate a model from db -assert category2.dict(exclude_unset=True) == {'id': 1, 'items': [], +assert category2.model_dump(exclude_unset=True) == {'id': 1, 'items': [], 'name': 'Test 2', 'visibility': True} ``` @@ -162,15 +162,15 @@ class Item(ormar.Model): category = Category() # note that Integer pk is by default autoincrement so optional -assert category.dict() == {'id': None, 'items': [], 'name': 'Test', 'visibility': True} -assert category.dict(exclude_defaults=True) == {'items': []} +assert category.model_dump() == {'id': None, 'items': [], 'name': 'Test', 'visibility': True} +assert category.model_dump(exclude_defaults=True) == {'items': []} # save and reload the data await category.save() category2 = await Category.objects.get() -assert category2.dict() == {'id': 1, 'items': [], 'name': 'Test', 'visibility': True} -assert category2.dict(exclude_defaults=True) == {'id': 1, 'items': []} +assert category2.model_dump() == {'id': 1, 'items': [], 'name': 'Test', 'visibility': True} +assert category2.model_dump(exclude_defaults=True) == {'id': 1, 'items': []} ``` ### exclude_none @@ -204,16 +204,16 @@ class Item(ormar.Model): category = Category(name=None) -assert category.dict() == {'id': None, 'items': [], 'name': None, +assert category.model_dump() == {'id': None, 'items': [], 'name': None, 'visibility': True} # note the id is not set yet so None and excluded -assert category.dict(exclude_none=True) == {'items': [], 'visibility': True} +assert category.model_dump(exclude_none=True) == {'items': [], 'visibility': True} await category.save() category2 = await Category.objects.get() -assert category2.dict() == {'id': 1, 'items': [], 'name': None, +assert category2.model_dump() == {'id': 1, 'items': [], 'name': None, 'visibility': True} -assert category2.dict(exclude_none=True) == {'id': 1, 'items': [], +assert category2.model_dump(exclude_none=True) == {'id': 1, 'items': [], 'visibility': True} ``` @@ -235,8 +235,8 @@ class Item(ormar.Model): name: str = ormar.String(max_length=100) item1 = Item(id=1, name="Test Item") -assert item1.dict() == {"id": 1, "name": "Test Item"} -assert item1.dict(exclude_primary_keys=True) == {"name": "Test Item"} +assert item1.model_dump() == {"id": 1, "name": "Test Item"} +assert item1.model_dump(exclude_primary_keys=True) == {"name": "Test Item"} ``` ### exclude_through_models (`ormar` only) @@ -280,7 +280,7 @@ await Item(**item_dict).save_related(follow=True, save_all=True) item = await Item.objects.select_related("categories").get() # by default you can see the through models (itemcategory) -assert item.dict() == {'id': 1, 'name': 'test', +assert item.model_dump() == {'id': 1, 'name': 'test', 'categories': [ {'id': 1, 'name': 'test cat', 'itemcategory': {'id': 1, 'category': None, 'item': None}}, @@ -289,7 +289,7 @@ assert item.dict() == {'id': 1, 'name': 'test', ]} # you can exclude those fields/ models -assert item.dict(exclude_through_models=True) == { +assert item.model_dump(exclude_through_models=True) == { 'id': 1, 'name': 'test', 'categories': [ {'id': 1, 'name': 'test cat'}, @@ -299,7 +299,7 @@ assert item.dict(exclude_through_models=True) == { ## json -`json()` has exactly the same parameters as `dict()` so check above. +`json()` has exactly the same parameters as `model_dump()` so check above. Of course the end result is a string with json representation and not a dictionary. @@ -647,7 +647,7 @@ to_exclude = { } # after excluding ids and through models you get exact same payload used to # construct whole tree -assert department_check.dict(exclude=to_exclude) == to_save +assert department_check.model_dump(exclude=to_exclude) == to_save ``` diff --git a/docs/relations/foreign-key.md b/docs/relations/foreign-key.md index 6cd05363a..2f880a1e9 100644 --- a/docs/relations/foreign-key.md +++ b/docs/relations/foreign-key.md @@ -45,7 +45,7 @@ But you cannot: * Access the related field from reverse model with `related_name` * Even if you `select_related` from reverse side of the model the returned models won't be populated in reversed instance (the join is not prevented so you still can `filter` and `order_by` over the relation) -* The relation won't be populated in `dict()` and `json()` +* The relation won't be populated in `model_dump()` and `json()` * You cannot pass the nested related objects when populating from dictionary or json (also through `fastapi`). It will be either ignored or error will be raised depending on `extra` setting in pydantic `Config`. Example: @@ -82,8 +82,8 @@ authors = ( assert authors[0].first_name == "Test" # note that posts are not populated for author even if explicitly -# included in select_related - note no posts in dict() -assert author.dict(exclude={"id"}) == {"first_name": "Test", "last_name": "Author"} +# included in select_related - note no posts in model_dump() +assert author.model_dump(exclude={"id"}) == {"first_name": "Test", "last_name": "Author"} # still can filter through fields of related model authors = await Author.objects.filter(posts__title="Test Post").all() @@ -246,7 +246,7 @@ You can setup the relation also with just the pk column value of the related mod Next option is with a dictionary of key-values of the related model. -You can build the dictionary yourself or get it from existing model with `dict()` method. +You can build the dictionary yourself or get it from existing model with `model_dump()` method. ```Python hl_lines="40-41" --8<-- "../docs_src/relations/docs001.py" diff --git a/docs/relations/many-to-many.md b/docs/relations/many-to-many.md index a6fc22925..d3eb7bdd4 100644 --- a/docs/relations/many-to-many.md +++ b/docs/relations/many-to-many.md @@ -89,7 +89,7 @@ flag of the `ManyToMany`. But you cannot: * access the related field from reverse model with `related_name` * even if you `select_related` from reverse side of the model the returned models won't be populated in reversed instance (the join is not prevented so you still can `filter` and `order_by` over the relation) - * the relation won't be populated in `dict()` and `json()` + * the relation won't be populated in `model_dump()` and `json()` * you cannot pass the nested related objects when populating from dictionary or json (also through `fastapi`). It will be either ignored or error will be raised depending on `extra` setting in pydantic `Config`. Example: @@ -126,8 +126,8 @@ categories = ( assert categories[0].first_name == "Test" # note that posts are not populated for author even if explicitly -# included in select_related - note no posts in dict() -assert news.dict(exclude={"id"}) == {"name": "News"} +# included in select_related - note no posts in model_dump() +assert news.model_dump(exclude={"id"}) == {"name": "News"} # still can filter through fields of related model categories = await Category.objects.filter(posts__title="Hello, M2M").all() diff --git a/docs/releases.md b/docs/releases.md index 096a91241..0dcca2264 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -588,7 +588,7 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. the `fields/exclude_fields` (from `QuerySet`) methods schema so when in doubt you can refer to docs in queries -> selecting subset of fields -> fields. * `Model.update()` method now accepts `_columns: List[str] = None` parameter, that accepts list of column names to update. If passed only those columns will be updated in database. Note that `update()` does not refresh the instance of the Model, so if you change more columns than you pass in `_columns` list your Model instance will have different values than the database! -* `Model.dict()` method previously included only directly related models or nested models if they were not nullable and not virtual, +* `Model.model_dump()` method previously included only directly related models or nested models if they were not nullable and not virtual, now all related models not previously visited without loops are included in `dict()`. This should be not breaking as just more data will be dumped to dict, but it should not be missing. * `QuerySet.delete(each=False, **kwargs)` previously required that you either pass a `filter` (by `**kwargs` or as a separate `filter()` call) or set `each=True` now also accepts @@ -941,7 +941,7 @@ as the same model can be registered multiple times and `ormar` needs to know fro * Performance optimization * Fix for bug with `pydantic_only` fields being required * Add `property_field` decorator that registers a function as a property that will - be included in `Model.dict()` and in `fastapi` response + be included in `Model.model_dump()` and in `fastapi` response * Update docs # 0.6.1 @@ -977,7 +977,7 @@ so now you can use those methods directly from relation # 0.5.3 -* Fixed bug in `Model.dict()` method that was ignoring exclude parameter and not include dictionary argument. +* Fixed bug in `Model.model_dump()` method that was ignoring exclude parameter and not include dictionary argument. # 0.5.2 @@ -1020,7 +1020,7 @@ so now you can use those methods directly from relation # 0.4.3 -* include properties in models.dict() and model.json() +* include properties in models.model_dump() and model.json() # 0.4.2 diff --git a/docs/signals.md b/docs/signals.md index ce6b2612c..2c33eebdd 100644 --- a/docs/signals.md +++ b/docs/signals.md @@ -75,7 +75,7 @@ You can define same receiver for multiple models at once by passing a list of mo # define a dummy debug function @pre_update([Album, Track]) async def before_update(sender, instance, **kwargs): - print(f"{sender.get_name()}: {instance.json()}: {kwargs}") + print(f"{sender.get_name()}: {instance.model_dump_json()}: {kwargs}") ``` Of course you can also create multiple functions for the same signal and model. Each of them will run at each signal. @@ -83,7 +83,7 @@ Of course you can also create multiple functions for the same signal and model. ```python @pre_update(Album) async def before_update(sender, instance, **kwargs): - print(f"{sender.get_name()}: {instance.json()}: {kwargs}") + print(f"{sender.get_name()}: {instance.model_dump_json()}: {kwargs}") @pre_update(Album) async def before_update2(sender, instance, **kwargs): @@ -100,7 +100,7 @@ class AlbumAuditor: async def before_save(self, sender, instance, **kwargs): await AuditLog( - event_type=f"{self.event_type}_SAVE", event_log=instance.json() + event_type=f"{self.event_type}_SAVE", event_log=instance.model_dump_json() ).save() auditor = AlbumAuditor() diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index f3aa2b2ae..392036c78 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -359,7 +359,7 @@ async def _upsert_through_model( ].through.get_name() through = getattr(instance, through_name) if through: - through_dict = through.dict(exclude=through.extract_related_names()) + through_dict = through.model_dump(exclude=through.extract_related_names()) else: through_dict = {} await getattr( diff --git a/ormar/models/model.py b/ormar/models/model.py index db2ec0321..f527485a0 100644 --- a/ormar/models/model.py +++ b/ormar/models/model.py @@ -344,5 +344,5 @@ async def load_all( queryset = queryset.order_by(order_by) instance = await queryset.select_related(relations).get(pk=self.pk) self._orm.clear() - self.update_from_dict(instance.dict()) + self.update_from_dict(instance.model_dump()) return self diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 37f474881..354d4c162 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -196,7 +196,7 @@ def __getattr__(self, item: str) -> Any: def __getstate__(self) -> Dict[Any, Any]: state = super().__getstate__() - self_dict = self.dict() + self_dict = self.model_dump() state["__dict__"].update(**self_dict) return state @@ -600,7 +600,7 @@ def _extract_nested_models_from_list( result = [] for model in models: try: - model_dict = model.dict( + model_dict = model.model_dump( relation_map=relation_map, include=include, exclude=exclude, @@ -669,7 +669,7 @@ def populate_through_models( for through_field in through_fields_to_populate: through_instance = getattr(model, through_field.name) if through_instance: - model_dict[through_field.name] = through_instance.dict() + model_dict[through_field.name] = through_instance.model_dump() @classmethod def _skip_ellipsis( @@ -677,7 +677,7 @@ def _skip_ellipsis( ) -> Union[Set, Dict, None]: """ Helper to traverse the include/exclude dictionaries. - In dict() Ellipsis should be skipped as it indicates all fields required + In model_dump() Ellipsis should be skipped as it indicates all fields required and not the actual set/dict with fields names. :param items: current include/exclude value @@ -754,7 +754,7 @@ def _extract_nested_models( # noqa: CCR001, CFQ002 exclude_through_models=exclude_through_models, ) elif nested_model is not None: - model_dict = nested_model.dict( + model_dict = nested_model.model_dump( relation_map=self._skip_ellipsis( relation_map, field, default_return=dict() ), @@ -931,6 +931,10 @@ def model_dump( # type: ignore # noqa A003 return dict_instance + @typing_extensions.deprecated( + "The `json` method is deprecated; use `model_dump_json` instead.", + category=OrmarDeprecatedSince020, + ) def json( # type: ignore # noqa A003 self, *, @@ -943,6 +947,35 @@ def json( # type: ignore # noqa A003 exclude_primary_keys: bool = False, exclude_through_models: bool = False, **dumps_kwargs: Any, + ) -> str: + warnings.warn( + "The `json` method is deprecated; use `model_dump_json` instead.", + DeprecationWarning, + ) + return self.model_dump_json( + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_primary_keys=exclude_primary_keys, + exclude_through_models=exclude_through_models, + **dumps_kwargs, + ) + + def model_dump_json( # type: ignore # noqa A003 + self, + *, + include: Union[Set, Dict, None] = None, + exclude: Union[Set, Dict, None] = None, + by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_primary_keys: bool = False, + exclude_through_models: bool = False, + **dumps_kwargs: Any, ) -> str: """ Generate a JSON representation of the model, `include` and `exclude` @@ -951,7 +984,7 @@ def json( # type: ignore # noqa A003 `encoder` is an optional function to supply as `default` to json.dumps(), other arguments as per `json.dumps()`. """ - data = self.dict( + data = self.model_dump( include=include, exclude=exclude, by_alias=by_alias, diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index 1ffc4dcb0..257415c1b 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -1153,7 +1153,7 @@ async def bulk_create(self, objects: List["T"]) -> None: ready_objects = [] for obj in objects: - ready_objects.append(obj.prepare_model_to_save(obj.dict())) + ready_objects.append(obj.prepare_model_to_save(obj.model_dump())) await asyncio.sleep(0) # Allow context switching to prevent blocking # don't use execute_many, as in databases it's executed in a loop @@ -1202,7 +1202,7 @@ async def bulk_update( # noqa: CCR001 columns = [self.model.get_column_alias(k) for k in columns] for obj in objects: - new_kwargs = obj.dict() + new_kwargs = obj.model_dump() if new_kwargs.get(pk_name) is None: raise ModelPersistenceError( "You cannot update unsaved objects. " diff --git a/tests/test_deferred/test_more_same_table_joins.py b/tests/test_deferred/test_more_same_table_joins.py index 820187ae1..38c73bd38 100644 --- a/tests/test_deferred/test_more_same_table_joins.py +++ b/tests/test_deferred/test_more_same_table_joins.py @@ -102,7 +102,7 @@ async def test_model_multiple_instances_of_same_table_in_schema(): ).all() assert classes[0].name == "Math" assert classes[0].students[0].name == "Jane" - assert len(classes[0].dict().get("students")) == 2 + assert len(classes[0].model_dump().get("students")) == 2 assert classes[0].teachers[0].category.department.name == "Law Department" assert classes[0].students[0].category.department.name == "Math Department" @@ -116,7 +116,7 @@ async def test_load_all_multiple_instances_of_same_table_in_schema(): await math_class.load_all(follow=True) assert math_class.students[0].name == "Jane" - assert len(math_class.dict().get("students")) == 2 + assert len(math_class.model_dump().get("students")) == 2 assert math_class.teachers[0].category.department.name == "Law Department" assert math_class.students[0].category.department.name == "Math Department" @@ -140,7 +140,7 @@ async def test_filter_groups_with_instances_of_same_table_in_schema(): ) assert math_class.name == "Math" assert math_class.students[0].name == "Jane" - assert len(math_class.dict().get("students")) == 2 + assert len(math_class.model_dump().get("students")) == 2 assert math_class.teachers[0].category.department.name == "Law Department" assert math_class.students[0].category.department.name == "Math Department" diff --git a/tests/test_deferred/test_same_table_joins.py b/tests/test_deferred/test_same_table_joins.py index 8372c5bf5..17667db9c 100644 --- a/tests/test_deferred/test_same_table_joins.py +++ b/tests/test_deferred/test_same_table_joins.py @@ -104,7 +104,7 @@ async def test_model_multiple_instances_of_same_table_in_schema(): assert classes[0].name == "Math" assert classes[0].students[0].name == "Jane" - assert len(classes[0].dict().get("students")) == 2 + assert len(classes[0].model_dump().get("students")) == 2 # since it's going from schoolclass => teacher # => schoolclass (same class) department is already populated diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index bb6ca6965..a42684031 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -80,13 +80,13 @@ def sample_data(): def test_dumping_to_dict_no_exclusion(sample_data): item1, item2 = sample_data - dict1 = item1.dict() + dict1 = item1.model_dump() assert dict1["name"] == "Teddy Bear" assert dict1["category"]["name"] == "Toys" assert dict1["category"]["tier"]["name"] == "Tier I" assert dict1["created_by"]["email"] == "test@test.com" - dict2 = item2.dict() + dict2 = item2.model_dump() assert dict2["name"] == "M16" assert dict2["category"]["name"] == "Weapons" assert dict2["created_by"]["email"] == "test@test.com" diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index 9eb6c2c91..c79ce17f7 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -206,7 +206,7 @@ async def test_excluding_nested_lists_in_dump(): manufacturer = await Company.objects.select_related("cars").get( name="Toyota" ) - assert manufacturer.dict() == { + assert manufacturer.model_dump() == { "cars": [ { "aircon_type": "Manual", diff --git a/tests/test_exclude_include_dict/test_pydantic_dict_params.py b/tests/test_exclude_include_dict/test_pydantic_dict_params.py index 40bbdc01d..3a572d9df 100644 --- a/tests/test_exclude_include_dict/test_pydantic_dict_params.py +++ b/tests/test_exclude_include_dict/test_pydantic_dict_params.py @@ -48,17 +48,17 @@ def create_test_database(): async def test_exclude_default(): async with database: category = Category() - assert category.dict() == { + assert category.model_dump() == { "id": None, "items": [], "name": "Test", "visibility": True, } - assert category.dict(exclude_defaults=True) == {"items": []} + assert category.model_dump(exclude_defaults=True) == {"items": []} await category.save() category2 = await Category.objects.get() - assert category2.dict() == { + assert category2.model_dump() == { "id": 1, "items": [], "name": "Test", diff --git a/tests/test_fastapi/test_excludes_with_get_pydantic.py b/tests/test_fastapi/test_excludes_with_get_pydantic.py index ca4f42160..0db526ced 100644 --- a/tests/test_fastapi/test_excludes_with_get_pydantic.py +++ b/tests/test_fastapi/test_excludes_with_get_pydantic.py @@ -39,7 +39,7 @@ def create_test_database(): async def create_category(category: Category): - return await Category(**category.dict()).save() + return await Category(**category.model_dump()).save() create_category.__annotations__["category"] = Category.get_pydantic(exclude={"id"}) @@ -55,7 +55,7 @@ async def create_selfref( exclude={"children__name"} # noqa: F821 ), ): - selfr = SelfRef(**selfref.dict()) + selfr = SelfRef(**selfref.model_dump()) await selfr.save() if selfr.children: for child in selfr.children: @@ -107,12 +107,12 @@ async def test_read_main(): assert self_ref.id == 3 assert self_ref.name == "test3" assert self_ref.parent is None - assert self_ref.children[0].dict() == {"id": 4} + assert self_ref.children[0].model_dump() == {"id": 4} response = await client.get("/selfrefs/3/") assert response.status_code == 200 check_children = SelfRef(**response.json()) - assert check_children.children[0].dict() == { + assert check_children.children[0].model_dump() == { "children": [], "id": 4, "name": "selfref", @@ -122,7 +122,7 @@ async def test_read_main(): response = await client.get("/selfrefs/2/") assert response.status_code == 200 check_children = SelfRef(**response.json()) - assert check_children.dict() == { + assert check_children.model_dump() == { "children": [], "id": 2, "name": "test2", @@ -132,7 +132,7 @@ async def test_read_main(): response = await client.get("/selfrefs/1/") assert response.status_code == 200 check_children = SelfRef(**response.json()) - assert check_children.dict() == { + assert check_children.model_dump() == { "children": [{"id": 2, "name": "test2"}], "id": 1, "name": "test", diff --git a/tests/test_fastapi/test_excluding_fields.py b/tests/test_fastapi/test_excluding_fields.py index e783a313f..6a11e7b53 100644 --- a/tests/test_fastapi/test_excluding_fields.py +++ b/tests/test_fastapi/test_excluding_fields.py @@ -70,26 +70,26 @@ async def create_item(item: Item): @app.get("/items/{item_id}") async def get_item(item_id: int): item = await Item.objects.select_related("categories").get(pk=item_id) - return item.dict(exclude_primary_keys=True, exclude_through_models=True) + return item.model_dump(exclude_primary_keys=True, exclude_through_models=True) @app.get("/categories/{category_id}") async def get_category(category_id: int): category = await Category.objects.select_related("items").get(pk=category_id) - return category.dict(exclude_primary_keys=True) + return category.model_dump(exclude_primary_keys=True) @app.get("/categories/nt/{category_id}") async def get_category_no_through(category_id: int): category = await Category.objects.select_related("items").get(pk=category_id) - result = category.dict(exclude_through_models=True) + result = category.model_dump(exclude_through_models=True) return result @app.get("/categories/ntp/{category_id}") async def get_category_no_pk_through(category_id: int): category = await Category.objects.select_related("items").get(pk=category_id) - return category.dict(exclude_through_models=True, exclude_primary_keys=True) + return category.model_dump(exclude_through_models=True, exclude_primary_keys=True) @pytest.mark.asyncio diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index 96a61362a..a3735c967 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -121,7 +121,8 @@ async def test_all_endpoints(): assert item.pk is not None response = await client.post( - "/items/add_category/", json={"item": item.dict(), "category": category} + "/items/add_category/", + json={"item": item.model_dump(), "category": category}, ) assert response.status_code == 200 item = Item(**response.json()) @@ -129,7 +130,8 @@ async def test_all_endpoints(): assert item.categories[0].name == "test cat" await client.post( - "/items/add_category/", json={"item": item.dict(), "category": category2} + "/items/add_category/", + json={"item": item.model_dump(), "category": category2}, ) response = await client.get("/items/") diff --git a/tests/test_fastapi/test_inheritance_concrete_fastapi.py b/tests/test_fastapi/test_inheritance_concrete_fastapi.py index 0c3fbd180..7f2a25488 100644 --- a/tests/test_fastapi/test_inheritance_concrete_fastapi.py +++ b/tests/test_fastapi/test_inheritance_concrete_fastapi.py @@ -136,7 +136,7 @@ async def test_read_main(): assert cat.created_date is not None assert cat.id == 1 - cat_dict = cat.dict() + cat_dict = cat.model_dump() cat_dict["updated_date"] = cat_dict["updated_date"].strftime( "%Y-%m-%d %H:%M:%S.%f" ) @@ -162,11 +162,14 @@ async def test_inheritance_with_relation(): truck_dict = dict( name="Shelby wanna be", max_capacity=1400, - owner=sam.dict(), - co_owner=joe.dict(), + owner=sam.model_dump(), + co_owner=joe.model_dump(), ) bus_dict = dict( - name="Unicorn", max_persons=50, owner=sam.dict(), co_owner=joe.dict() + name="Unicorn", + max_persons=50, + owner=sam.model_dump(), + co_owner=joe.model_dump(), ) unicorn = Bus(**(await client.post("/buses/", json=bus_dict)).json()) shelby = Truck(**(await client.post("/trucks/", json=truck_dict)).json()) @@ -203,21 +206,25 @@ async def test_inheritance_with_m2m_relation(): joe = Person(**(await client.post("/persons/", json={"name": "Joe"})).json()) alex = Person(**(await client.post("/persons/", json={"name": "Alex"})).json()) - truck_dict = dict(name="Shelby wanna be", max_capacity=2000, owner=sam.dict()) - bus_dict = dict(name="Unicorn", max_persons=80, owner=sam.dict()) + truck_dict = dict( + name="Shelby wanna be", max_capacity=2000, owner=sam.model_dump() + ) + bus_dict = dict(name="Unicorn", max_persons=80, owner=sam.model_dump()) unicorn = Bus2(**(await client.post("/buses2/", json=bus_dict)).json()) shelby = Truck2(**(await client.post("/trucks2/", json=truck_dict)).json()) unicorn = Bus2( **( - await client.post(f"/buses2/{unicorn.pk}/add_coowner/", json=joe.dict()) + await client.post( + f"/buses2/{unicorn.pk}/add_coowner/", json=joe.model_dump() + ) ).json() ) unicorn = Bus2( **( await client.post( - f"/buses2/{unicorn.pk}/add_coowner/", json=alex.dict() + f"/buses2/{unicorn.pk}/add_coowner/", json=alex.model_dump() ) ).json() ) @@ -234,7 +241,7 @@ async def test_inheritance_with_m2m_relation(): assert unicorn.co_owners[1] == alex assert unicorn.max_persons == 80 - await client.post(f"/trucks2/{shelby.pk}/add_coowner/", json=alex.dict()) + await client.post(f"/trucks2/{shelby.pk}/add_coowner/", json=alex.model_dump()) shelby = Truck2( **( diff --git a/tests/test_fastapi/test_inheritance_mixins_fastapi.py b/tests/test_fastapi/test_inheritance_mixins_fastapi.py index c57d88f1b..20223c038 100644 --- a/tests/test_fastapi/test_inheritance_mixins_fastapi.py +++ b/tests/test_fastapi/test_inheritance_mixins_fastapi.py @@ -68,7 +68,7 @@ async def test_read_main(): assert cat.created_date is not None assert cat.id == 1 - cat_dict = cat.dict() + cat_dict = cat.model_dump() cat_dict["updated_date"] = cat_dict["updated_date"].strftime( "%Y-%m-%d %H:%M:%S.%f" ) diff --git a/tests/test_fastapi/test_json_field_fastapi.py b/tests/test_fastapi/test_json_field_fastapi.py index 744e23638..d58f6ed52 100644 --- a/tests/test_fastapi/test_json_field_fastapi.py +++ b/tests/test_fastapi/test_json_field_fastapi.py @@ -117,10 +117,10 @@ class Thing2(ormar.Model): async def test_setting_values_after_init(): async with database: t1 = Thing(id="67a82813-d90c-45ff-b546-b4e38d7030d7", name="t1", js=["thing1"]) - assert '["thing1"]' in t1.json() + assert '["thing1"]' in t1.model_dump_json() await t1.save() - t1.json() - assert '["thing1"]' in t1.json() + t1.model_dump_json() + assert '["thing1"]' in t1.model_dump_json() assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).json() await t1.update() diff --git a/tests/test_fastapi/test_more_reallife_fastapi.py b/tests/test_fastapi/test_more_reallife_fastapi.py index b67dbfa10..0fcd01501 100644 --- a/tests/test_fastapi/test_more_reallife_fastapi.py +++ b/tests/test_fastapi/test_more_reallife_fastapi.py @@ -94,7 +94,7 @@ async def get_item(item_id: int): @app.put("/items/{item_id}") async def update_item(item_id: int, item: Item): item_db = await Item.objects.get(pk=item_id) - return await item_db.update(**item.dict()) + return await item_db.update(**item.model_dump()) @app.delete("/items/{item_id}") @@ -120,8 +120,8 @@ async def test_all_endpoints(): assert items[0] == item item.name = "New name" - response = await client.put(f"/items/{item.pk}", json=item.dict()) - assert response.json() == item.dict() + response = await client.put(f"/items/{item.pk}", json=item.model_dump()) + assert response.json() == item.model_dump() response = await client.get("/items") items = [Item(**item) for item in response.json()] diff --git a/tests/test_fastapi/test_nested_saving.py b/tests/test_fastapi/test_nested_saving.py index 952a69056..48d9144a8 100644 --- a/tests/test_fastapi/test_nested_saving.py +++ b/tests/test_fastapi/test_nested_saving.py @@ -119,7 +119,7 @@ async def get_department(department_name: str): department = await Department.objects.select_all(follow=True).get( department_name=department_name ) - return department.dict(exclude=to_exclude) + return department.model_dump(exclude=to_exclude) @app.get("/departments/{department_name}/second") @@ -127,7 +127,7 @@ async def get_department_exclude(department_name: str): department = await Department.objects.select_all(follow=True).get( department_name=department_name ) - return department.dict(exclude=to_exclude_ormar) + return department.model_dump(exclude=to_exclude_ormar) @app.get("/departments/{department_name}/exclude") @@ -135,7 +135,7 @@ async def get_department_exclude_all(department_name: str): department = await Department.objects.select_all(follow=True).get( department_name=department_name ) - return department.dict(exclude=exclude_all) + return department.model_dump(exclude=exclude_all) @pytest.mark.asyncio diff --git a/tests/test_fastapi/test_recursion_error.py b/tests/test_fastapi/test_recursion_error.py index 3fa832ed2..9eb34b07a 100644 --- a/tests/test_fastapi/test_recursion_error.py +++ b/tests/test_fastapi/test_recursion_error.py @@ -120,7 +120,7 @@ async def get_current_user(): async def create_quiz_lol( quiz_input: QuizInput, user: User = Depends(get_current_user) ): - quiz = Quiz(**quiz_input.dict(), user_id=user.id) + quiz = Quiz(**quiz_input.model_dump(), user_id=user.id) return await quiz.save() diff --git a/tests/test_fastapi/test_wekref_exclusion.py b/tests/test_fastapi/test_wekref_exclusion.py index 9f304a5c4..83149e0cd 100644 --- a/tests/test_fastapi/test_wekref_exclusion.py +++ b/tests/test_fastapi/test_wekref_exclusion.py @@ -97,7 +97,7 @@ async def get_test_3(): ot = await OtherThing.objects.select_related("things").get() # exclude unwanted field while ot is still in scope # in order not to pass it to fastapi - return [t.dict(exclude={"other_thing"}) for t in ot.things] + return [t.model_dump(exclude={"other_thing"}) for t in ot.things] @app.get("/test/4", response_model=List[Thing], response_model_exclude={"other_thing"}) diff --git a/tests/test_model_definition/test_aliases.py b/tests/test_model_definition/test_aliases.py index 8d01616c9..230e3d58d 100644 --- a/tests/test_model_definition/test_aliases.py +++ b/tests/test_model_definition/test_aliases.py @@ -172,7 +172,7 @@ async def test_working_with_aliases_get_or_create(): assert artist == artist2 assert created is False - art3 = artist2.dict() + art3 = artist2.model_dump() art3["born_year"] = 2019 await Artist.objects.update_or_create(**art3) diff --git a/tests/test_model_definition/test_model_construct.py b/tests/test_model_definition/test_model_construct.py index 628e8588a..aaab0a5b9 100644 --- a/tests/test_model_definition/test_model_construct.py +++ b/tests/test_model_definition/test_model_construct.py @@ -73,7 +73,7 @@ async def test_construct_with_empty_relation(): comp2 = Company.model_construct( **dict(name="Banzai", hq=None, founded=1988) ) - assert comp.dict() == comp2.dict() + assert comp.model_dump() == comp2.model_dump() @pytest.mark.asyncio @@ -83,7 +83,7 @@ async def test_init_and_construct_has_same_effect(): hq = await HQ.objects.create(name="Main") comp = Company(name="Banzai", hq=hq, founded=1988) comp2 = Company.model_construct(**dict(name="Banzai", hq=hq, founded=1988)) - assert comp.dict() == comp2.dict() + assert comp.model_dump() == comp2.model_dump() comp3 = Company.model_construct( **dict(name="Banzai", hq=hq.dict(), founded=1988) diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index a817f2785..1f099100e 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -322,7 +322,7 @@ async def test_uuid_column(): assert item2.id == item3.id assert isinstance(item3.id, uuid.UUID) - u3 = await UUIDSample2(**u1.dict()).save() + u3 = await UUIDSample2(**u1.model_dump()).save() u1_2 = await UUIDSample.objects.get(pk=u3.id) assert u1_2 == u1 diff --git a/tests/test_model_definition/test_properties.py b/tests/test_model_definition/test_properties.py index 293830a3e..955e443b4 100644 --- a/tests/test_model_definition/test_properties.py +++ b/tests/test_model_definition/test_properties.py @@ -52,7 +52,7 @@ async def test_sort_order_on_main_model(): await Song.objects.create(name="Song 2", sort_order=2) songs = await Song.objects.all() - song_dict = [song.dict() for song in songs] + song_dict = [song.model_dump() for song in songs] assert all("sorted_name" in x for x in song_dict) assert all( x["sorted_name"] == f"{x['sort_order']}: {x['name']}" for x in song_dict @@ -60,7 +60,7 @@ async def test_sort_order_on_main_model(): song_json = [song.json() for song in songs] assert all("sorted_name" in x for x in song_json) - check_include = songs[0].dict(include={"sample"}) + check_include = songs[0].model_dump(include={"sample"}) assert "sample" in check_include assert "sample2" not in check_include assert "sorted_name" not in check_include diff --git a/tests/test_model_definition/test_pydantic_only_fields.py b/tests/test_model_definition/test_pydantic_only_fields.py index bc43249a3..06aaec835 100644 --- a/tests/test_model_definition/test_pydantic_only_fields.py +++ b/tests/test_model_definition/test_pydantic_only_fields.py @@ -64,14 +64,14 @@ async def test_pydantic_only_fields(): album = await Album.objects.fields({"name", "timestamp"}).get() assert album.timestamp is None - test_dict = album.dict() + test_dict = album.model_dump() assert "timestamp" in test_dict assert test_dict["timestamp"] is None assert album.name30 == "Hitchcock_30" album.timestamp = datetime.datetime.now() - test_dict = album.dict() + test_dict = album.model_dump() assert "timestamp" in test_dict assert test_dict["timestamp"] is not None assert test_dict.get("name10") == "Hitchcock_10" diff --git a/tests/test_model_definition/test_save_status.py b/tests/test_model_definition/test_save_status.py index 224040c02..c142a5874 100644 --- a/tests/test_model_definition/test_save_status.py +++ b/tests/test_model_definition/test_save_status.py @@ -212,7 +212,7 @@ async def test_queryset_methods(): assert comp3.pk == comp.pk assert created is False - update_dict = comp.dict() + update_dict = comp.model_dump() update_dict["founded"] = 2010 comp = await Company.objects.update_or_create(**update_dict) assert comp.saved diff --git a/tests/test_model_methods/test_save_related_uuid.py b/tests/test_model_methods/test_save_related_uuid.py index ad1568f19..db7f10180 100644 --- a/tests/test_model_methods/test_save_related_uuid.py +++ b/tests/test_model_methods/test_save_related_uuid.py @@ -83,4 +83,4 @@ async def test_uuid_pk_in_save_related(): "id": ..., "courses": {"id": ..., "students": {"id", "studentcourse"}}, } - assert department_check.dict(exclude=to_exclude) == to_save + assert department_check.model_dump(exclude=to_exclude) == to_save diff --git a/tests/test_relations/test_skipping_reverse.py b/tests/test_relations/test_skipping_reverse.py index b683b2c6c..bdce81d65 100644 --- a/tests/test_relations/test_skipping_reverse.py +++ b/tests/test_relations/test_skipping_reverse.py @@ -119,7 +119,7 @@ async def test_quering_of_related_model_works_but_no_result(cleanup): post_categories = await post.categories.all() assert len(post_categories) == 1 - assert "posts" not in post.dict().get("categories", [])[0] + assert "posts" not in post.model_dump().get("categories", [])[0] assert news == await post.categories.get(name="News") @@ -133,7 +133,7 @@ async def test_quering_of_related_model_works_but_no_result(cleanup): .get() ) assert category == news - assert "posts" not in category.dict() + assert "posts" not in category.model_dump() # relation not in json category2 = ( diff --git a/tests/test_signals/test_signals.py b/tests/test_signals/test_signals.py index 1f574b6fc..740a92c35 100644 --- a/tests/test_signals/test_signals.py +++ b/tests/test_signals/test_signals.py @@ -321,7 +321,7 @@ async def before_save(sender, instance, **kwargs): assert audits[0].event_type == "PRE_SAVE_cover" assert audits[0].event_log.get("title") == cover.title assert audits[1].event_type == "PRE_SAVE_album" - assert audits[1].event_log.get("cover") == album.cover.dict( + assert audits[1].event_log.get("cover") == album.cover.model_dump( exclude={"albums"} ) From 13400087f732c5c1f2dbabfbf44882d8363b19c7 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 16:18:08 +0100 Subject: [PATCH 63/95] finish switching dict() -> model_dump() --- docs/releases.md | 2 +- docs_src/fastapi/docs001.py | 2 +- docs_src/relations/docs001.py | 2 +- examples/fastapi_quick_start.py | 2 +- .../test_complex_relation_tree_performance.py | 2 +- .../test_dumping_model_to_dict.py | 18 ++++++++--------- .../test_excluding_fields_in_fastapi.py | 6 +++--- .../test_excluding_subset_of_columns.py | 2 +- .../test_pydantic_dict_params.py | 20 +++++++++---------- .../test_inheritance_concrete_fastapi.py | 4 +++- .../test_geting_pydantic_models.py | 6 +++--- .../test_inheritance_of_property_fields.py | 4 ++-- .../test_nested_models_pydantic.py | 2 +- .../test_model_construct.py | 12 ++++++----- .../test_model_definition/test_properties.py | 2 +- 15 files changed, 45 insertions(+), 41 deletions(-) diff --git a/docs/releases.md b/docs/releases.md index 0dcca2264..bc2e393a1 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -1020,7 +1020,7 @@ so now you can use those methods directly from relation # 0.4.3 -* include properties in models.model_dump() and model.json() +* include properties in models.model_dump() and model.model_dump_json() # 0.4.2 diff --git a/docs_src/fastapi/docs001.py b/docs_src/fastapi/docs001.py index 75ba527ae..b19912691 100644 --- a/docs_src/fastapi/docs001.py +++ b/docs_src/fastapi/docs001.py @@ -67,7 +67,7 @@ async def create_category(category: Category): @app.put("/items/{item_id}") async def get_item(item_id: int, item: Item): item_db = await Item.objects.get(pk=item_id) - return await item_db.update(**item.dict()) + return await item_db.update(**item.model_dump()) @app.delete("/items/{item_id}") diff --git a/docs_src/relations/docs001.py b/docs_src/relations/docs001.py index ac9e0b1d0..ccf85413a 100644 --- a/docs_src/relations/docs001.py +++ b/docs_src/relations/docs001.py @@ -39,7 +39,7 @@ class Course(ormar.Model): course2 = Course(name="Math II", completed=False, department=department.pk) # set up a relation with dictionary corresponding to related model -course3 = Course(name="Math III", completed=False, department=department.dict()) +course3 = Course(name="Math III", completed=False, department=department.model_dump()) # explicitly set up None course4 = Course(name="Math III", completed=False, department=None) diff --git a/examples/fastapi_quick_start.py b/examples/fastapi_quick_start.py index e2d2eb11b..8757cfb04 100644 --- a/examples/fastapi_quick_start.py +++ b/examples/fastapi_quick_start.py @@ -69,7 +69,7 @@ async def create_category(category: Category): @app.put("/items/{item_id}") async def get_item(item_id: int, item: Item): item_db = await Item.objects.get(pk=item_id) - return await item_db.update(**item.dict()) + return await item_db.update(**item.model_dump()) @app.delete("/items/{item_id}") diff --git a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py index f93766225..2cc5a076c 100644 --- a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py +++ b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py @@ -355,7 +355,7 @@ async def test_very_complex_relation_map(): await Release(**pay, tag=saved_tags[ind]).save() releases = await Release.objects.order_by(Release.id.desc()).all() - dicts = [release.dict() for release in releases] + dicts = [release.model_dump() for release in releases] result = [ { diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index a42684031..4a5eb0108 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -94,17 +94,17 @@ def test_dumping_to_dict_no_exclusion(sample_data): def test_dumping_to_dict_exclude_set(sample_data): item1, item2 = sample_data - dict3 = item2.dict(exclude={"name"}) + dict3 = item2.model_dump(exclude={"name"}) assert "name" not in dict3 assert dict3["category"]["name"] == "Weapons" assert dict3["created_by"]["email"] == "test@test.com" - dict4 = item2.dict(exclude={"category"}) + dict4 = item2.model_dump(exclude={"category"}) assert dict4["name"] == "M16" assert "category" not in dict4 assert dict4["created_by"]["email"] == "test@test.com" - dict5 = item2.dict(exclude={"category", "name"}) + dict5 = item2.model_dump(exclude={"category", "name"}) assert "name" not in dict5 assert "category" not in dict5 assert dict5["created_by"]["email"] == "test@test.com" @@ -112,7 +112,7 @@ def test_dumping_to_dict_exclude_set(sample_data): def test_dumping_to_dict_exclude_dict(sample_data): item1, item2 = sample_data - dict6 = item2.dict(exclude={"category": {"name"}, "name": ...}) + dict6 = item2.model_dump(exclude={"category": {"name"}, "name": ...}) assert "name" not in dict6 assert "category" in dict6 assert "name" not in dict6["category"] @@ -121,7 +121,7 @@ def test_dumping_to_dict_exclude_dict(sample_data): def test_dumping_to_dict_exclude_nested_dict(sample_data): item1, item2 = sample_data - dict1 = item2.dict(exclude={"category": {"tier": {"name"}}, "name": ...}) + dict1 = item2.model_dump(exclude={"category": {"tier": {"name"}}, "name": ...}) assert "name" not in dict1 assert "category" in dict1 assert dict1["category"]["name"] == "Weapons" @@ -131,7 +131,7 @@ def test_dumping_to_dict_exclude_nested_dict(sample_data): def test_dumping_to_dict_exclude_and_include_nested_dict(sample_data): item1, item2 = sample_data - dict1 = item2.dict( + dict1 = item2.model_dump( exclude={"category": {"tier": {"name"}}}, include={"name", "category"} ) assert dict1.get("name") == "M16" @@ -140,7 +140,7 @@ def test_dumping_to_dict_exclude_and_include_nested_dict(sample_data): assert "created_by" not in dict1 assert dict1["category"]["tier"].get("name") is None - dict2 = item1.dict( + dict2 = item1.model_dump( exclude={"id": ...}, include={"name": ..., "category": {"name": ..., "tier": {"id"}}}, ) @@ -154,7 +154,7 @@ def test_dumping_to_dict_exclude_and_include_nested_dict(sample_data): def test_dumping_dict_without_primary_keys(sample_data): item1, item2 = sample_data - dict1 = item2.dict(exclude_primary_keys=True) + dict1 = item2.model_dump(exclude_primary_keys=True) assert dict1 == { "category": {"name": "Weapons", "tier": {"name": "Tier I"}}, "created_by": { @@ -168,7 +168,7 @@ def test_dumping_dict_without_primary_keys(sample_data): }, "name": "M16", } - dict2 = item1.dict(exclude_primary_keys=True) + dict2 = item1.model_dump(exclude_primary_keys=True) assert dict2 == { "category": {"name": "Toys", "tier": {"name": "Tier I"}}, "created_by": { diff --git a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py index c67b1c995..34df91416 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py @@ -130,7 +130,7 @@ async def create_user(user: User): @app.post("/users2/", response_model=User) async def create_user2(user: User): user = await user.save() - return user.dict(exclude={"password"}) + return user.model_dump(exclude={"password"}) @app.post("/users3/", response_model=UserBase) @@ -140,7 +140,7 @@ async def create_user3(user: User2): @app.post("/users4/") async def create_user4(user: User2): - return (await user.save()).dict(exclude={"password"}) + return (await user.save()).model_dump(exclude={"password"}) @app.post("/random/", response_model=RandomModel) @@ -284,7 +284,7 @@ async def test_excluding_property_field_in_endpoints2(): @post_save(RandomModel) async def after_save(sender, instance, **kwargs): - dummy_registry[instance.pk] = instance.dict() + dummy_registry[instance.pk] = instance.model_dump() client = AsyncClient(app=app, base_url="http://testserver") async with client as client, LifespanManager(app): diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index c79ce17f7..3d13942b5 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -229,7 +229,7 @@ async def test_excluding_nested_lists_in_dump(): "id": toyota.id, "name": "Toyota", } - assert manufacturer.dict(exclude_list=True) == { + assert manufacturer.model_dump(exclude_list=True) == { "founded": 1937, "id": toyota.id, "name": "Toyota", diff --git a/tests/test_exclude_include_dict/test_pydantic_dict_params.py b/tests/test_exclude_include_dict/test_pydantic_dict_params.py index 3a572d9df..a481193fd 100644 --- a/tests/test_exclude_include_dict/test_pydantic_dict_params.py +++ b/tests/test_exclude_include_dict/test_pydantic_dict_params.py @@ -64,21 +64,21 @@ async def test_exclude_default(): "name": "Test", "visibility": True, } - assert category2.dict(exclude_defaults=True) == {"id": 1, "items": []} - assert category2.json(exclude_defaults=True) == '{"id":1,"items":[]}' + assert category2.model_dump(exclude_defaults=True) == {"id": 1, "items": []} + assert category2.model_dump_json(exclude_defaults=True) == '{"id":1,"items":[]}' @pytest.mark.asyncio async def test_exclude_none(): async with database: category = Category(id=2, name=None) - assert category.dict() == { + assert category.model_dump() == { "id": 2, "items": [], "name": None, "visibility": True, } - assert category.dict(exclude_none=True) == { + assert category.model_dump(exclude_none=True) == { "id": 2, "items": [], "visibility": True, @@ -86,13 +86,13 @@ async def test_exclude_none(): await category.save() category2 = await Category.objects.get() - assert category2.dict() == { + assert category2.model_dump() == { "id": 2, "items": [], "name": None, "visibility": True, } - assert category2.dict(exclude_none=True) == { + assert category2.model_dump(exclude_none=True) == { "id": 2, "items": [], "visibility": True, @@ -106,13 +106,13 @@ async def test_exclude_none(): async def test_exclude_unset(): async with database: category = Category(id=3, name="Test 2") - assert category.dict() == { + assert category.model_dump() == { "id": 3, "items": [], "name": "Test 2", "visibility": True, } - assert category.dict(exclude_unset=True) == { + assert category.model_dump(exclude_unset=True) == { "id": 3, "items": [], "name": "Test 2", @@ -120,7 +120,7 @@ async def test_exclude_unset(): await category.save() category2 = await Category.objects.get() - assert category2.dict() == { + assert category2.model_dump() == { "id": 3, "items": [], "name": "Test 2", @@ -128,7 +128,7 @@ async def test_exclude_unset(): } # NOTE how after loading from db all fields are set explicitly # as this is what happens when you populate a model from db - assert category2.dict(exclude_unset=True) == { + assert category2.model_dump(exclude_unset=True) == { "id": 3, "items": [], "name": "Test 2", diff --git a/tests/test_fastapi/test_inheritance_concrete_fastapi.py b/tests/test_fastapi/test_inheritance_concrete_fastapi.py index 7f2a25488..c8f4251f0 100644 --- a/tests/test_fastapi/test_inheritance_concrete_fastapi.py +++ b/tests/test_fastapi/test_inheritance_concrete_fastapi.py @@ -245,7 +245,9 @@ async def test_inheritance_with_m2m_relation(): shelby = Truck2( **( - await client.post(f"/trucks2/{shelby.pk}/add_coowner/", json=joe.dict()) + await client.post( + f"/trucks2/{shelby.pk}/add_coowner/", json=joe.model_dump() + ) ).json() ) diff --git a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py index e00147c7a..fcf6c61bb 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py +++ b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py @@ -113,13 +113,13 @@ def test_initializing_pydantic_model(): } PydanticCategory = Category.get_pydantic() ormar_cat = Category(**data) - assert ormar_cat.dict() == data + assert ormar_cat.model_dump() == data cat = PydanticCategory(**data) - assert cat.dict() == data + assert cat.model_dump() == data data = {"id": 1, "name": "test"} cat = PydanticCategory(**data) - assert cat.dict() == {**data, "items": None} + assert cat.model_dump() == {**data, "items": None} def test_getting_pydantic_model_include(): diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py index 11740b0de..a9d0cf166 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py @@ -59,7 +59,7 @@ def create_test_database(): def test_property_fields_are_inherited(): foo = Foo(name="foo") assert foo.prefixed_name == "prefix_foo" - assert foo.dict() == { + assert foo.model_dump() == { "name": "foo", "id": None, "double_prefixed_name": "prefix2_foo", @@ -68,4 +68,4 @@ def test_property_fields_are_inherited(): bar = Bar(name="bar") assert bar.prefixed_name == "baz_bar" - assert bar.dict() == {"name": "bar", "id": None, "prefixed_name": "baz_bar"} + assert bar.model_dump() == {"name": "bar", "id": None, "prefixed_name": "baz_bar"} diff --git a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py index e0939f2c1..08e99c9fc 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py @@ -68,7 +68,7 @@ def test_casts_properly(): } test_package = TicketPackage(**payload) TicketPackageOut = TicketPackage.get_pydantic(exclude={"ticket"}) - parsed = TicketPackageOut(**test_package.dict()).dict() + parsed = TicketPackageOut(**test_package.model_dump()).model_dump() assert "ticket" not in parsed assert "package" in parsed assert "library" in parsed.get("package") diff --git a/tests/test_model_definition/test_model_construct.py b/tests/test_model_definition/test_model_construct.py index aaab0a5b9..1ef8ec559 100644 --- a/tests/test_model_definition/test_model_construct.py +++ b/tests/test_model_definition/test_model_construct.py @@ -86,9 +86,9 @@ async def test_init_and_construct_has_same_effect(): assert comp.model_dump() == comp2.model_dump() comp3 = Company.model_construct( - **dict(name="Banzai", hq=hq.dict(), founded=1988) + **dict(name="Banzai", hq=hq.model_dump(), founded=1988) ) - assert comp.dict() == comp3.dict() + assert comp.model_dump() == comp3.model_dump() @pytest.mark.asyncio @@ -99,7 +99,9 @@ async def test_init_and_construct_has_same_effect_with_m2m(): n2 = await NickNames(name="test2").save() hq = HQ(name="Main", nicks=[n1, n2]) hq2 = HQ.model_construct(**dict(name="Main", nicks=[n1, n2])) - assert hq.dict() == hq2.dict() + assert hq.model_dump() == hq2.model_dump() - hq3 = HQ.model_construct(**dict(name="Main", nicks=[n1.dict(), n2.dict()])) - assert hq.dict() == hq3.dict() + hq3 = HQ.model_construct( + **dict(name="Main", nicks=[n1.model_dump(), n2.model_dump()]) + ) + assert hq.model_dump() == hq3.model_dump() diff --git a/tests/test_model_definition/test_properties.py b/tests/test_model_definition/test_properties.py index 955e443b4..2bccc85ea 100644 --- a/tests/test_model_definition/test_properties.py +++ b/tests/test_model_definition/test_properties.py @@ -65,7 +65,7 @@ async def test_sort_order_on_main_model(): assert "sample2" not in check_include assert "sorted_name" not in check_include - check_include = songs[0].dict(exclude={"sample"}) + check_include = songs[0].model_dump(exclude={"sample"}) assert "sample" not in check_include assert "sample2" in check_include assert "sorted_name" in check_include From d55e07bc3bc4495abfc2c40b80685f478912cde7 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 17:17:40 +0100 Subject: [PATCH 64/95] finish switching json() -> model_dump_json() --- .../test_pydantic_dict_params.py | 3 ++- .../test_schema_not_allowed_params.py | 2 +- .../test_model_definition/test_properties.py | 2 +- tests/test_relations/test_skipping_reverse.py | 4 +-- tests/test_signals/test_signals.py | 25 ++++++++++--------- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/test_exclude_include_dict/test_pydantic_dict_params.py b/tests/test_exclude_include_dict/test_pydantic_dict_params.py index a481193fd..a58bdc635 100644 --- a/tests/test_exclude_include_dict/test_pydantic_dict_params.py +++ b/tests/test_exclude_include_dict/test_pydantic_dict_params.py @@ -98,7 +98,8 @@ async def test_exclude_none(): "visibility": True, } assert ( - category2.json(exclude_none=True) == '{"id":2,"visibility":true,"items":[]}' + category2.model_dump_json(exclude_none=True) + == '{"id":2,"visibility":true,"items":[]}' ) diff --git a/tests/test_fastapi/test_schema_not_allowed_params.py b/tests/test_fastapi/test_schema_not_allowed_params.py index e6123bf5f..7384f5825 100644 --- a/tests/test_fastapi/test_schema_not_allowed_params.py +++ b/tests/test_fastapi/test_schema_not_allowed_params.py @@ -22,7 +22,7 @@ class Author(ormar.Model): def test_schema_not_allowed(): - schema = Author.schema() + schema = Author.model_json_schema() for field_schema in schema.get("properties").values(): for key in field_schema.keys(): assert "_" not in key, f"Found illegal field in openapi schema: {key}" diff --git a/tests/test_model_definition/test_properties.py b/tests/test_model_definition/test_properties.py index 2bccc85ea..4d54bf73c 100644 --- a/tests/test_model_definition/test_properties.py +++ b/tests/test_model_definition/test_properties.py @@ -57,7 +57,7 @@ async def test_sort_order_on_main_model(): assert all( x["sorted_name"] == f"{x['sort_order']}: {x['name']}" for x in song_dict ) - song_json = [song.json() for song in songs] + song_json = [song.model_dump_json() for song in songs] assert all("sorted_name" in x for x in song_json) check_include = songs[0].model_dump(include={"sample"}) diff --git a/tests/test_relations/test_skipping_reverse.py b/tests/test_relations/test_skipping_reverse.py index bdce81d65..b4d2f38e7 100644 --- a/tests/test_relations/test_skipping_reverse.py +++ b/tests/test_relations/test_skipping_reverse.py @@ -142,9 +142,9 @@ async def test_quering_of_related_model_works_but_no_result(cleanup): .get() ) assert category2 == news - assert "posts" not in category2.json() + assert "posts" not in category2.model_dump_json() - assert "posts" not in Category.schema().get("properties") + assert "posts" not in Category.model_json_schema().get("properties") @pytest.mark.asyncio diff --git a/tests/test_signals/test_signals.py b/tests/test_signals/test_signals.py index 740a92c35..251e91734 100644 --- a/tests/test_signals/test_signals.py +++ b/tests/test_signals/test_signals.py @@ -105,42 +105,42 @@ async def test_signal_functions(cleanup): async def before_save(sender, instance, **kwargs): await AuditLog( event_type=f"PRE_SAVE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() @post_save(Album) async def after_save(sender, instance, **kwargs): await AuditLog( event_type=f"POST_SAVE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() @pre_update(Album) async def before_update(sender, instance, **kwargs): await AuditLog( event_type=f"PRE_UPDATE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() @post_update(Album) async def after_update(sender, instance, **kwargs): await AuditLog( event_type=f"POST_UPDATE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() @pre_delete(Album) async def before_delete(sender, instance, **kwargs): await AuditLog( event_type=f"PRE_DELETE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() @post_delete(Album) async def after_delete(sender, instance, **kwargs): await AuditLog( event_type=f"POST_DELETE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() @post_bulk_update(Album) @@ -148,7 +148,7 @@ async def after_bulk_update(sender, instances, **kwargs): for it in instances: await AuditLog( event_type=f"BULK_POST_UPDATE_{sender.get_name()}", - event_log=it.json(), + event_log=it.model_dump_json(), ).save() album = await Album.objects.create(name="Venice") @@ -228,14 +228,14 @@ async def test_multiple_signals(cleanup): async def before_save(sender, instance, **kwargs): await AuditLog( event_type=f"PRE_SAVE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() @pre_save(Album) async def before_save2(sender, instance, **kwargs): await AuditLog( event_type=f"PRE_SAVE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() album = await Album.objects.create(name="Miami") @@ -263,7 +263,7 @@ class AlbumAuditor: async def before_save(sender, instance, **kwargs): await AuditLog( event_type=f"{AlbumAuditor.event_type}_SAVE", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() album = await Album.objects.create(name="Colorado") @@ -286,7 +286,8 @@ def __init__(self): async def before_save(self, sender, instance, **kwargs): await AuditLog( - event_type=f"{self.event_type}_SAVE", event_log=instance.json() + event_type=f"{self.event_type}_SAVE", + event_log=instance.model_dump_json(), ).save() auditor = AlbumAuditor() @@ -310,7 +311,7 @@ async def test_multiple_senders_signal(cleanup): async def before_save(sender, instance, **kwargs): await AuditLog( event_type=f"PRE_SAVE_{sender.get_name()}", - event_log=instance.json(), + event_log=instance.model_dump_json(), ).save() cover = await Cover(title="Blue").save() From 36aa05b9d1ddab5fbc57c143ea9e5886e62e0765 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 18:01:37 +0100 Subject: [PATCH 65/95] remove fully pydantic_only --- README.md | 2 - docs/fastapi/requests.md | 3 +- docs/fastapi/response.md | 3 +- docs/fields/common-parameters.md | 15 -- docs/index.md | 2 - docs/models/index.md | 134 ++---------------- docs_src/models/docs005.py | 3 - docs_src/models/docs014.py | 3 +- ormar/exceptions.py | 1 - ormar/fields/base.py | 10 -- ormar/fields/foreign_key.py | 1 - ormar/fields/many_to_many.py | 1 - ormar/fields/model_fields.py | 13 +- ormar/fields/through_field.py | 1 - ormar/models/helpers/sqlalchemy.py | 20 +-- ormar/models/mixins/save_mixin.py | 10 +- .../test_excluding_fields_in_fastapi.py | 12 +- .../test_model_definition.py | 14 -- .../test_pydantic_only_fields.py | 3 +- 19 files changed, 26 insertions(+), 225 deletions(-) diff --git a/README.md b/README.md index 05632be25..1d1ed24a3 100644 --- a/README.md +++ b/README.md @@ -655,7 +655,6 @@ The following keyword arguments are supported on all field types. * `unique: bool` * `choices: typing.Sequence` * `name: str` -* `pydantic_only: bool` All fields are required unless one of the following is set: @@ -665,7 +664,6 @@ All fields are required unless one of the following is set: * `server_default` - Set a default value for the field on server side (like sqlalchemy's `func.now()`). **Not available for relation fields** * `primary key` with `autoincrement` - When a column is set to primary key and autoincrement is set on this column. Autoincrement is set by default on int primary keys. -* `pydantic_only` - Field is available only as normal pydantic field, not stored in the database. ### Available signals diff --git a/docs/fastapi/requests.md b/docs/fastapi/requests.md index 426373c6c..361cbbea4 100644 --- a/docs/fastapi/requests.md +++ b/docs/fastapi/requests.md @@ -126,8 +126,7 @@ Sample: import pydantic class UserCreate(pydantic.BaseModel): - class Config: - orm_mode = True + model_config = pydantic.ConfigDict(from_attributes=True) email: str first_name: str diff --git a/docs/fastapi/response.md b/docs/fastapi/response.md index 8b1349922..66e0591a8 100644 --- a/docs/fastapi/response.md +++ b/docs/fastapi/response.md @@ -229,8 +229,7 @@ Sample: import pydantic class UserBase(pydantic.BaseModel): - class Config: - orm_mode = True + model_config = pydantic.ConfigDict(from_attributes=True) email: str first_name: str diff --git a/docs/fields/common-parameters.md b/docs/fields/common-parameters.md index 79ce92016..bee0f4150 100644 --- a/docs/fields/common-parameters.md +++ b/docs/fields/common-parameters.md @@ -29,7 +29,6 @@ Automatically changed to True if user provide one of the following: * `default` value or function is provided * `server_default` value or function is provided * `autoincrement` is set on `Integer` `primary_key` field -* **[DEPRECATED]**`pydantic_only=True` is set Specifies if field is optional or required, used both with sql and pydantic. @@ -167,20 +166,6 @@ Sets the unique constraint on a table's column. Used in sql only. -## pydantic_only (**DEPRECATED**) - -**This parameter is deprecated and will be removed in one of next releases!** - -**To check how to declare pydantic only fields that are not saved into database see [pydantic fields section](pydantic-fields.md)** - -`pydantic_only`: `bool` = `False` - -Prevents creation of a sql column for given field. - -Used for data related to given model but not to be stored in the database. - -Used in pydantic only. - ## overwrite_pydantic_type By default, ormar uses predefined pydantic field types that it applies on model creation (hence the type hints are optional). diff --git a/docs/index.md b/docs/index.md index 5eaaacf9b..bb75b91aa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -664,7 +664,6 @@ The following keyword arguments are supported on all field types. * `unique: bool` * `choices: typing.Sequence` * `name: str` - * `pydantic_only: bool` All fields are required unless one of the following is set: @@ -674,7 +673,6 @@ All fields are required unless one of the following is set: * `server_default` - Set a default value for the field on server side (like sqlalchemy's `func.now()`). **Not available for relation fields** * `primary key` with `autoincrement` - When a column is set to primary key and autoincrement is set on this column. Autoincrement is set by default on int primary keys. - * `pydantic_only` - Field is available only as normal pydantic field, not stored in the database. ### Available signals diff --git a/docs/models/index.md b/docs/models/index.md index ce6ae9843..4c3239350 100644 --- a/docs/models/index.md +++ b/docs/models/index.md @@ -42,15 +42,15 @@ id: int = ormar.Integer(primary_key=True, autoincrement=False) #### Non Database Fields Note that if you need a normal pydantic field in your model (used to store value on model or pass around some value) you can define a -field with parameter `pydantic_only=True`. +field like usual in pydantic. Fields created like this are added to the `pydantic` model fields -> so are subject to validation according to `Field` type, -also appear in `model_dump()` and `json()` result. +also appear in `model_dump()` and `model_dump_json()` result. The difference is that **those fields are not saved in the database**. So they won't be included in underlying sqlalchemy `columns`, or `table` variables (check [Internals][Internals] section below to see how you can access those if you need). -Subsequently `pydantic_only` fields won't be included in migrations or any database operation (like `save`, `update` etc.) +Subsequently, pydantic fields won't be included in migrations or any database operation (like `save`, `update` etc.) Fields like those can be passed around into payload in `fastapi` request and will be returned in `fastapi` response (of course only if you set their value somewhere in your code as the value is **not** fetched from the db. @@ -58,21 +58,17 @@ If you pass a value in `fastapi` `request` and return the same instance that `fa you should get back exactly same value in `response`.). !!!warning - `pydantic_only=True` fields are always **Optional** and it cannot be changed (otherwise db load validation would fail) - -!!!tip - `pydantic_only=True` fields are a good solution if you need to pass additional information from outside of your API - (i.e. frontend). They are not stored in db but you can access them in your `APIRoute` code and they also have `pydantic` validation. + pydantic fields have to be always **Optional** and it cannot be changed (otherwise db load validation would fail) ```Python hl_lines="18" --8<-- "../docs_src/models/docs014.py" ``` -If you combine `pydantic_only=True` field with `default` parameter and do not pass actual value in request you will always get default value. +If you set pydantic field with `default` parameter and do not pass actual value in request you will always get default value. Since it can be a function you can set `default=datetime.datetime.now` and get current timestamp each time you call an endpoint etc. !!!note - Note that both `pydantic_only` and `property_field` decorated field can be included/excluded in both `model_dump()` and `fastapi` + Note, that both pydantic and calculated_fields decorated field can be included/excluded in both `model_dump()` and `fastapi` response with `include`/`exclude` and `response_model_include`/`response_model_exclude` accordingly. ```python @@ -89,8 +85,8 @@ class User(ormar.Model): first_name: str = ormar.String(max_length=255) last_name: str = ormar.String(max_length=255) category: str = ormar.String(max_length=255, nullable=True) - timestamp: datetime.datetime = ormar.DateTime( - pydantic_only=True, default=datetime.datetime.now + timestamp: datetime.datetime = pydantic.Field( + default=datetime.datetime.now ) # <==related of code removed for clarity==> @@ -130,120 +126,6 @@ def test_excluding_fields_in_endpoints(): # <==related of code removed for clarity==> ``` -#### Property fields - -Sometimes it's desirable to do some kind of calculation on the model instance. One of the most common examples can be concatenating -two or more fields. Imagine you have `first_name` and `last_name` fields on your model, but would like to have `full_name` in the result -of the `fastapi` query. - -You can create a new `pydantic` model with a `method` that accepts only `self` (so like default python `@property`) -and populate it in your code. - -But it's so common that `ormar` has you covered. You can "materialize" a `property_field` on you `Model`. - -!!!warning - `property_field` fields are always **Optional** and it cannot be changed (otherwise db load validation would fail) - -```Python hl_lines="20-22" ---8<-- "../docs_src/models/docs015.py" -``` - -!!!warning - The decorated function has to accept only one parameter, and that parameter have to be `self`. - - If you try to decorate a function with more parameters `ormar` will raise `ModelDefinitionError`. - - Sample: - - ```python - # will raise ModelDefinitionError - @property_field - def prefixed_name(self, prefix="prefix_"): - return 'custom_prefix__' + self.name - - # will raise ModelDefinitionError - # (calling first param something else than 'self' is a bad practice anyway) - @property_field - def prefixed_name(instance): - return 'custom_prefix__' + self.name - ``` - -Note that `property_field` decorated methods do not go through verification (but that might change in future) and are only available -in the response from `fastapi` and `model_dump()` and `json()` methods. You cannot pass a value for this field in the request -(or rather you can but it will be discarded by ormar so really no point but no Exception will be raised). - -!!!note - Note that both `pydantic_only` and `property_field` decorated field can be included/excluded in both `model_dump()` and `fastapi` - response with `include`/`exclude` and `response_model_include`/`response_model_exclude` accordingly. - -!!!tip - Note that `@property_field` decorator is designed to replace the python `@property` decorator, you do not have to combine them. - - In theory you can cause `ormar` have a failsafe mechanism, but note that i.e. `mypy` will complain about re-decorating a property. - - ```python - # valid and working but unnecessary and mypy will complain - @property_field - @property - def prefixed_name(self): - return 'custom_prefix__' + self.name - ``` - -```python -# <==related of code removed for clarity==> -def gen_pass(): # note: NOT production ready - choices = string.ascii_letters + string.digits + "!@#$%^&*()" - return "".join(random.choice(choices) for _ in range(20)) - -class RandomModel(ormar.Model): - class Meta: - tablename: str = "random_users" - metadata = metadata - database = database - - include_props_in_dict = True - - id: int = ormar.Integer(primary_key=True) - password: str = ormar.String(max_length=255, default=gen_pass) - first_name: str = ormar.String(max_length=255, default="John") - last_name: str = ormar.String(max_length=255) - created_date: datetime.datetime = ormar.DateTime( - server_default=sqlalchemy.func.now() - ) - - @property_field - def full_name(self) -> str: - return " ".join([self.first_name, self.last_name]) - -# <==related of code removed for clarity==> -app =FastAPI() - -# explicitly exclude property_field in this endpoint -@app.post("/random/", response_model=RandomModel, response_model_exclude={"full_name"}) -async def create_user(user: RandomModel): - return await user.save() - -# <==related of code removed for clarity==> - -def test_excluding_property_field_in_endpoints2(): - client = TestClient(app) - with client as client: - RandomModel.Meta.include_props_in_dict = True - user3 = {"last_name": "Test"} - response = client.post("/random3/", json=user3) - assert list(response.json().keys()) == [ - "id", - "password", - "first_name", - "last_name", - "created_date", - ] - # despite being decorated with property_field if you explictly exclude it it will be gone - assert response.json().get("full_name") is None - -# <==related of code removed for clarity==> -``` - #### Fields names vs Column names By default names of the fields will be used for both the underlying `pydantic` model and `sqlalchemy` table. diff --git a/docs_src/models/docs005.py b/docs_src/models/docs005.py index e34bed14b..a95d477d5 100644 --- a/docs_src/models/docs005.py +++ b/docs_src/models/docs005.py @@ -36,7 +36,6 @@ class Course(ormar.Model): 'sql_nullable': False, 'index': False, 'unique': False, - 'pydantic_only': False, 'choices': False, 'virtual': None, 'is_multi': None, @@ -80,7 +79,6 @@ class Course(ormar.Model): 'sql_nullable': False, 'index': False, 'unique': False, - 'pydantic_only': False, 'choices': False, 'virtual': None, 'is_multi': None, @@ -122,7 +120,6 @@ class Course(ormar.Model): 'sql_nullable': True, 'index': False, 'unique': False, - 'pydantic_only': False, 'choices': False, 'virtual': None, 'is_multi': None, diff --git a/docs_src/models/docs014.py b/docs_src/models/docs014.py index 0429b931c..5f5a57375 100644 --- a/docs_src/models/docs014.py +++ b/docs_src/models/docs014.py @@ -1,5 +1,6 @@ import databases import ormar +import pydantic import sqlalchemy database = databases.Database("sqlite:///db.sqlite") @@ -15,4 +16,4 @@ class Course(ormar.Model): id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) completed: bool = ormar.Boolean(default=False) - non_db_field: str = ormar.String(max_length=100, pydantic_only=True) + non_db_field: str = pydantic.Field(max_length=100) diff --git a/ormar/exceptions.py b/ormar/exceptions.py index 12e2e3afc..47172000b 100644 --- a/ormar/exceptions.py +++ b/ormar/exceptions.py @@ -19,7 +19,6 @@ class ModelDefinitionError(AsyncOrmException): * defining a Field without required parameters * defining a model with more than one primary_key * defining a model without primary_key - * setting primary_key column as pydantic_only """ pass diff --git a/ormar/fields/base.py b/ormar/fields/base.py index 23e670a14..297f83abd 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -1,4 +1,3 @@ -import warnings from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Type, Union import sqlalchemy @@ -44,15 +43,6 @@ def __init__(self, **kwargs: Any) -> None: self.sql_nullable: bool = kwargs.pop("sql_nullable", False) self.index: bool = kwargs.pop("index", False) self.unique: bool = kwargs.pop("unique", False) - self.pydantic_only: bool = kwargs.pop("pydantic_only", False) - if self.pydantic_only: - warnings.warn( - "Parameter `pydantic_only` is deprecated and will " - "be removed in one of the next releases.\n You can declare " - "pydantic fields in a normal way. \n Check documentation: " - "https://collerek.github.io/ormar/fields/pydantic-fields", - DeprecationWarning, - ) self.choices: Sequence = kwargs.pop("choices", False) self.virtual: bool = kwargs.pop( diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index 510c7bb10..a867c39b5 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -297,7 +297,6 @@ def ForeignKey( # type: ignore # noqa CFQ002 virtual=virtual, primary_key=False, index=False, - pydantic_only=False, default=None, server_default=None, onupdate=onupdate, diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 341159b85..1d757b6d9 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -161,7 +161,6 @@ def ManyToMany( # type: ignore virtual=virtual, primary_key=False, index=False, - pydantic_only=False, default=None, server_default=None, owner=owner, diff --git a/ormar/fields/model_fields.py b/ormar/fields/model_fields.py index ed931c082..fa3616380 100644 --- a/ormar/fields/model_fields.py +++ b/ormar/fields/model_fields.py @@ -24,7 +24,6 @@ def is_field_nullable( nullable: Optional[bool], default: Any, server_default: Any, - pydantic_only: Optional[bool], ) -> bool: """ Checks if the given field should be nullable/ optional based on parameters given. @@ -35,17 +34,11 @@ def is_field_nullable( :type default: Any :param server_default: function to be called as default by sql server :type server_default: Any - :param pydantic_only: flag if fields should not be included in the sql table - :type pydantic_only: Optional[bool] :return: result of the check :rtype: bool """ if nullable is None: - return ( - default is not None - or server_default is not None - or (pydantic_only is not None and pydantic_only) - ) + return default is not None or server_default is not None return nullable @@ -79,7 +72,6 @@ def __new__(cls, *args: Any, **kwargs: Any) -> BaseField: # type: ignore server_default = kwargs.pop("server_default", None) nullable = kwargs.pop("nullable", None) sql_nullable = kwargs.pop("sql_nullable", None) - pydantic_only = kwargs.pop("pydantic_only", False) primary_key = kwargs.pop("primary_key", False) autoincrement = kwargs.pop("autoincrement", False) @@ -91,7 +83,7 @@ def __new__(cls, *args: Any, **kwargs: Any) -> BaseField: # type: ignore overwrite_pydantic_type = kwargs.pop("overwrite_pydantic_type", None) nullable = is_field_nullable( - nullable, default, server_default, pydantic_only + nullable, default, server_default ) or is_auto_primary_key(primary_key, autoincrement) sql_nullable = ( False @@ -120,7 +112,6 @@ def __new__(cls, *args: Any, **kwargs: Any) -> BaseField: # type: ignore sql_nullable=sql_nullable, index=kwargs.pop("index", False), unique=kwargs.pop("unique", False), - pydantic_only=pydantic_only, autoincrement=autoincrement, column_type=cls.get_column_type( **kwargs, sql_nullable=sql_nullable, enum_class=enum_class diff --git a/ormar/fields/through_field.py b/ormar/fields/through_field.py index e494d90f7..616581622 100644 --- a/ormar/fields/through_field.py +++ b/ormar/fields/through_field.py @@ -55,7 +55,6 @@ def Through( # noqa CFQ002 column_type=None, primary_key=False, index=False, - pydantic_only=False, default=None, server_default=None, is_relation=True, diff --git a/ormar/models/helpers/sqlalchemy.py b/ormar/models/helpers/sqlalchemy.py index 7c2830fb5..fdcdfd35a 100644 --- a/ormar/models/helpers/sqlalchemy.py +++ b/ormar/models/helpers/sqlalchemy.py @@ -100,10 +100,9 @@ def check_pk_column_validity( ) -> Optional[str]: """ Receives the field marked as primary key and verifies if the pkname - was not already set (only one allowed per model) and if field is not marked - as pydantic_only as it needs to be a database field. + was not already set (only one allowed per model). - :raises ModelDefintionError: if pkname already set or field is pydantic_only + :raises ModelDefintionError: if pkname already set :param field_name: name of field :type field_name: str :param field: ormar.Field @@ -115,8 +114,6 @@ def check_pk_column_validity( """ if pkname is not None: raise ormar.ModelDefinitionError("Only one primary key column is allowed.") - if field.pydantic_only: - raise ormar.ModelDefinitionError("Primary key column cannot be pydantic only") return field_name @@ -134,11 +131,7 @@ def sqlalchemy_columns_from_model_fields( are leading to the same related model only one can have empty related_name param. Also related_names have to be unique. - Trigger validation of primary_key - only one and required pk can be set, - cannot be pydantic_only. - - Append fields to columns if it's not pydantic_only, - virtual ForeignKey or ManyToMany field. + Trigger validation of primary_key - only one and required pk can be set Sets `owner` on each model_field as reference to newly created Model. @@ -168,11 +161,6 @@ def _process_fields( Helper method. Populates pkname and columns. - Trigger validation of primary_key - only one and required pk can be set, - cannot be pydantic_only. - - Append fields to columns if it's not pydantic_only, - virtual ForeignKey or ManyToMany field. Sets `owner` on each model_field as reference to newly created Model. @@ -217,7 +205,7 @@ def _is_db_field(field: "BaseField") -> bool: :return: result of the check :rtype: bool """ - return not field.pydantic_only and not field.virtual and not field.is_multi + return not field.virtual and not field.is_multi def populate_meta_tablename_columns_and_pk( diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index 392036c78..25e87c2d2 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -96,9 +96,7 @@ def _remove_not_ormar_fields(cls, new_kwargs: dict) -> dict: :return: dictionary of model that is about to be saved :rtype: Dict[str, str] """ - ormar_fields = { - k for k, v in cls.ormar_config.model_fields.items() if not v.pydantic_only - } + ormar_fields = {k for k, v in cls.ormar_config.model_fields.items()} new_kwargs = {k: v for k, v in new_kwargs.items() if k in ormar_fields} return new_kwargs @@ -229,11 +227,7 @@ def populate_default_values(cls, new_kwargs: Dict) -> Dict: :rtype: Dict """ for field_name, field in cls.ormar_config.model_fields.items(): - if ( - field_name not in new_kwargs - and field.has_default(use_server=False) - and not field.pydantic_only - ): + if field_name not in new_kwargs and field.has_default(use_server=False): new_kwargs[field_name] = field.get_default() # clear fields with server_default set as None if ( diff --git a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py index 34df91416..00bfe8ed8 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py @@ -11,7 +11,7 @@ from fastapi import FastAPI from httpx import AsyncClient from ormar import post_save -from pydantic import computed_field +from pydantic import ConfigDict, computed_field from tests.settings import DATABASE_URL @@ -38,8 +38,7 @@ async def shutdown() -> None: # note that you can set orm_mode here # and in this case UserSchema become unnecessary class UserBase(pydantic.BaseModel): - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) email: str first_name: str @@ -52,8 +51,7 @@ class UserCreateSchema(UserBase): class UserSchema(UserBase): - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) def gen_pass(): @@ -109,9 +107,7 @@ class User2(ormar.Model): first_name: str = ormar.String(max_length=255) last_name: str = ormar.String(max_length=255) category: str = ormar.String(max_length=255, nullable=True) - timestamp: datetime.datetime = ormar.DateTime( - pydantic_only=True, default=datetime.datetime.now - ) + timestamp: datetime.datetime = pydantic.Field(default=datetime.datetime.now) @pytest.fixture(autouse=True, scope="module") diff --git a/tests/test_model_definition/test_model_definition.py b/tests/test_model_definition/test_model_definition.py index f5021f04c..0393d5111 100644 --- a/tests/test_model_definition/test_model_definition.py +++ b/tests/test_model_definition/test_model_definition.py @@ -201,20 +201,6 @@ class ExampleModel2(Model): test_string: str = ormar.String(max_length=250, primary_key=True) -@typing.no_type_check -def test_setting_pk_column_as_pydantic_only_in_model_definition(): - with pytest.raises(ModelDefinitionError): - - class ExampleModel2(Model): - ormar_config = ormar.OrmarConfig( - tablename="example4", - database=database, - metadata=metadata, - ) - - test: int = ormar.Integer(primary_key=True, pydantic_only=True) - - @typing.no_type_check def test_decimal_error_in_model_definition(): with pytest.raises(ModelDefinitionError): diff --git a/tests/test_model_definition/test_pydantic_only_fields.py b/tests/test_model_definition/test_pydantic_only_fields.py index 06aaec835..f7c0d676a 100644 --- a/tests/test_model_definition/test_pydantic_only_fields.py +++ b/tests/test_model_definition/test_pydantic_only_fields.py @@ -2,6 +2,7 @@ import databases import ormar +import pydantic import pytest import sqlalchemy from pydantic import computed_field @@ -21,7 +22,7 @@ class Album(ormar.Model): id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) - timestamp: datetime.datetime = ormar.DateTime(pydantic_only=True) + timestamp: datetime.datetime = pydantic.Field(default=None) @computed_field def name10(self) -> str: From 4b6ed028fddbb8122e31261665a66991eb6207cd Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 18:18:05 +0100 Subject: [PATCH 66/95] switch to extra for payment card, change missed json calls --- poetry.lock | 20 ++++++++++++++++++- pyproject.toml | 1 + tests/test_fastapi/test_json_field_fastapi.py | 4 ++-- .../test_pydantic_fields.py | 3 ++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 00f0adb70..b803467ae 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1662,6 +1662,24 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pydantic-extra-types" +version = "2.5.0" +description = "Extra Pydantic types." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_extra_types-2.5.0-py3-none-any.whl", hash = "sha256:7346873019cac32061b471adf2cdac711664ddb7a6ede04219bed2da34888c4d"}, + {file = "pydantic_extra_types-2.5.0.tar.gz", hash = "sha256:46b85240093dc63ad4a8f3cab49e03d76ae0577e4f99e2bbff7d32f99d009bf9"}, +] + +[package.dependencies] +pydantic = ">=2.5.2" + +[package.extras] +all = ["pendulum (>=3.0.0,<4.0.0)", "phonenumbers (>=8,<9)", "pycountry (>=23,<24)", "python-ulid (>=1,<2)"] + [[package]] name = "pygments" version = "2.17.2" @@ -2479,4 +2497,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "0e2c8f7250939c5c4bff34bff3f06123668a8808b47ed6b52bc18dba1a80391f" +content-hash = "07ac72d838e4aba426f1b6e42c7ca4d341ffbac63c92a43075d1bcbab3296209" diff --git a/pyproject.toml b/pyproject.toml index ff30c9002..37a386012 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -131,6 +131,7 @@ nest-asyncio = "^1.5.6" pre-commit = "^2.21.0" httpx = "^0.24.1" asgi-lifespan = "^2.1.0" +pydantic-extra-types = "^2.5.0" [build-system] diff --git a/tests/test_fastapi/test_json_field_fastapi.py b/tests/test_fastapi/test_json_field_fastapi.py index d58f6ed52..ff11f458c 100644 --- a/tests/test_fastapi/test_json_field_fastapi.py +++ b/tests/test_fastapi/test_json_field_fastapi.py @@ -122,9 +122,9 @@ async def test_setting_values_after_init(): t1.model_dump_json() assert '["thing1"]' in t1.model_dump_json() - assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).json() + assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).model_dump_json() await t1.update() - assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).json() + assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).model_dump_json() @pytest.mark.asyncio diff --git a/tests/test_model_definition/test_pydantic_fields.py b/tests/test_model_definition/test_pydantic_fields.py index 4817b8a3e..df69a6163 100644 --- a/tests/test_model_definition/test_pydantic_fields.py +++ b/tests/test_model_definition/test_pydantic_fields.py @@ -5,7 +5,8 @@ import ormar import pytest import sqlalchemy -from pydantic import BaseModel, Field, HttpUrl, PaymentCardNumber +from pydantic import BaseModel, Field, HttpUrl +from pydantic_extra_types.payment import PaymentCardNumber from tests.settings import DATABASE_URL From ee4440bf71c742cf071b2b02de4a3beb0ae62701 Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 18:22:18 +0100 Subject: [PATCH 67/95] fix coverage - no more warnings internal --- ormar/warnings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ormar/warnings.py b/ormar/warnings.py index 4c14e80ad..55fcba4bf 100644 --- a/ormar/warnings.py +++ b/ormar/warnings.py @@ -25,7 +25,7 @@ def __init__( *args: object, since: Tuple[int, int], expected_removal: Optional[Tuple[int, int]] = None, - ) -> None: + ) -> None: # pragma: no cover super().__init__(message, *args) self.message = message.rstrip(".") self.since = since @@ -47,5 +47,5 @@ class OrmarDeprecatedSince020(OrmarDeprecationWarning): """A specific `OrmarDeprecationWarning` subclass defining functionality deprecated since Ormar 0.20.""" - def __init__(self, message: str, *args: object) -> None: + def __init__(self, message: str, *args: object) -> None: # pragma: no cover super().__init__(message, *args, since=(0, 20), expected_removal=(0, 30)) From 55f4c1378235ce2a917aba611de1af2389e3e20c Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 6 Feb 2024 18:25:22 +0100 Subject: [PATCH 68/95] fix coverage - no more warnings internal - part 2 --- ormar/models/newbasemodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 354d4c162..e4d6eb4d7 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -947,7 +947,7 @@ def json( # type: ignore # noqa A003 exclude_primary_keys: bool = False, exclude_through_models: bool = False, **dumps_kwargs: Any, - ) -> str: + ) -> str: # pragma: no cover warnings.warn( "The `json` method is deprecated; use `model_dump_json` instead.", DeprecationWarning, From b45d7762bb81f39604b5b7be31526d950eb2faa2 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 7 Feb 2024 20:19:09 +0100 Subject: [PATCH 69/95] split model_construct into own and pydantic parts --- ormar/models/newbasemodel.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index e4d6eb4d7..03743156f 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -1029,17 +1029,30 @@ def model_construct( if _fields_set is None: _fields_set = set(values.keys()) - _extra: dict[str, Any] | None = None - if cls.model_config.get("extra") == "allow": # pragma: no cover - _extra = {} - for k, v in values.items(): - _extra[k] = v - else: + extra_allowed = cls.model_config.get("extra") == "allow" + if not extra_allowed: fields_values.update(values) object.__setattr__(model, "__dict__", fields_values) model._initialize_internal_attributes() cls._construct_relations(model=model, values=values) object.__setattr__(model, "__pydantic_fields_set__", _fields_set) + return cls._pydantic_model_construct_finalizer( + model=model, extra_allowed=extra_allowed, values=values + ) + + @classmethod + def _pydantic_model_construct_finalizer( + cls: Type["T"], model: "T", extra_allowed: bool, **values: Any + ) -> "T": + """ + Recreate pydantic model_construct logic here as we do not call super method. + """ + _extra: Union[Dict[str, Any], None] = None + if extra_allowed: # pragma: no cover + _extra = {} + for k, v in values.items(): + _extra[k] = v + if not cls.__pydantic_root_model__: object.__setattr__(model, "__pydantic_extra__", _extra) From e68c3aae5dc82e6dd821948095de3ded000c4079 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 7 Feb 2024 20:49:15 +0100 Subject: [PATCH 70/95] split determine pydantic field type --- ormar/models/mixins/pydantic_mixin.py | 41 ++++++++++++++++++++------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/ormar/models/mixins/pydantic_mixin.py b/ormar/models/mixins/pydantic_mixin.py index fe3f71226..bd2e1a6f3 100644 --- a/ormar/models/mixins/pydantic_mixin.py +++ b/ormar/models/mixins/pydantic_mixin.py @@ -9,15 +9,18 @@ List, Optional, Set, + Tuple, Type, Union, cast, ) import pydantic +from pydantic import BaseModel from pydantic._internal._decorators import DecoratorInfos from pydantic.fields import FieldInfo +from ormar.fields import BaseField, ForeignKeyField, ManyToManyField from ormar.models.mixins.relation_mixin import RelationMixin # noqa: I100, I202 from ormar.queryset.utils import translate_list_to_dict @@ -114,17 +117,14 @@ def _determine_pydantic_field_type( field = cls.ormar_config.model_fields[name] target: Any = None if field.is_relation and name in relation_map: - target = field.to._convert_ormar_to_pydantic( - include=cls._skip_ellipsis(include, name), - exclude=cls._skip_ellipsis(exclude, name), - relation_map=cls._skip_ellipsis( - relation_map, name, default_return=dict() - ), + target, default = cls._determined_included_relation_field_type( + name=name, + field=field, + include=include, + exclude=exclude, + defaults=defaults, + relation_map=relation_map, ) - if field.is_multi or field.virtual: - target = List[target] # type: ignore - if field.nullable: - defaults[name] = None elif not field.is_relation: defaults[name] = cls.model_fields[name].default target = field.__type__ @@ -132,6 +132,27 @@ def _determine_pydantic_field_type( target = Optional[target] return target + @classmethod + def _determined_included_relation_field_type( + cls, + name: str, + field: Union[BaseField, ForeignKeyField, ManyToManyField], + include: Union[Set, Dict, None], + exclude: Union[Set, Dict, None], + defaults: Dict, + relation_map: Dict[str, Any], + ) -> Tuple[Type[BaseModel], Dict]: + target = field.to._convert_ormar_to_pydantic( + include=cls._skip_ellipsis(include, name), + exclude=cls._skip_ellipsis(exclude, name), + relation_map=cls._skip_ellipsis(relation_map, name, default_return=dict()), + ) + if field.is_multi or field.virtual: + target = List[target] # type: ignore + if field.nullable: + defaults[name] = None + return target, defaults + @classmethod def _copy_field_validators(cls, model: Type[pydantic.BaseModel]) -> None: """ From ab85c81c01998ee1538c7ed0f86352b696eed6a9 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 7 Feb 2024 21:18:11 +0100 Subject: [PATCH 71/95] change to new field validators --- docs_src/models/docs016.py | 3 ++- .../test_validators_in_generated_pydantic.py | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs_src/models/docs016.py b/docs_src/models/docs016.py index e1881d81d..6d456a4de 100644 --- a/docs_src/models/docs016.py +++ b/docs_src/models/docs016.py @@ -1,5 +1,6 @@ import databases import ormar +import pydantic import sqlalchemy database = databases.Database("sqlite:///db.sqlite") @@ -12,7 +13,7 @@ class Course(ormar.Model): metadata=metadata, ) - model_config = dict(allow_mutation=False) + model_config = pydantic.ConfigDict(frozen=True) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py index d8d4ee97e..e2ffe047f 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py @@ -2,10 +2,9 @@ import databases import ormar -import pydantic import pytest import sqlalchemy -from pydantic import ValidationError +from pydantic import ValidationError, field_validator from tests.settings import DATABASE_URL @@ -36,7 +35,7 @@ class ModelExample(ormar.Model): str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) enum_field: str = ormar.Enum(nullable=False, enum_class=EnumExample) - @pydantic.validator("str_field") + @field_validator("str_field") def validate_str_field(cls, v): if " " not in v: raise ValueError("must contain a space") From 80a93b430c75b9ed7ddbec8f989cd203ac2760e4 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 7 Feb 2024 22:45:02 +0100 Subject: [PATCH 72/95] fix benchmarks, add codspeed instead of pytest-benchmark, add action and gh workflow --- .github/workflows/benchmark.yml | 40 ++ benchmarks/conftest.py | 2 +- benchmarks/test_benchmark_bulk_create.py | 2 +- benchmarks/test_benchmark_create.py | 6 +- benchmarks/test_benchmark_init.py | 4 +- benchmarks/test_benchmark_save.py | 2 +- poetry.lock | 733 +++++++++++------------ pyproject.toml | 2 +- 8 files changed, 405 insertions(+), 386 deletions(-) create mode 100644 .github/workflows/benchmark.yml diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 000000000..9aa3cb194 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,40 @@ +name: codspeed-benchmarks + +on: + push: + branches: + - "master" # or "master" + pull_request: + branches: [ master, pydantic_v2 ] + # `workflow_dispatch` allows CodSpeed to trigger backtest + # performance analysis in order to generate initial data. + workflow_dispatch: + +jobs: + benchmarks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + with: + python-version: "3.11" + + - name: Install Poetry + uses: snok/install-poetry@v1.3.3 + with: + version: 1.4.2 + virtualenvs-create: false + + - name: Poetry details + run: | + poetry --version + poetry config --list + + - name: Install dependencies + run: poetry install --extras "all" + + - name: Run benchmarks + uses: CodSpeedHQ/action@v2 + with: + token: ${{ secrets.CODSPEED_TOKEN }} + run: poetry run pytest benchmarks/ --codspeed \ No newline at end of file diff --git a/benchmarks/conftest.py b/benchmarks/conftest.py index 7338a3b16..99cb8438e 100644 --- a/benchmarks/conftest.py +++ b/benchmarks/conftest.py @@ -83,7 +83,7 @@ async def authors_in_db(num_models: int): authors = [ Author( name="".join(random.sample(string.ascii_letters, 5)), - score=random.random() * 100, + score=int(random.random() * 100), ) for i in range(0, num_models) ] diff --git a/benchmarks/test_benchmark_bulk_create.py b/benchmarks/test_benchmark_bulk_create.py index 3869cd6f4..0e6be5b2c 100644 --- a/benchmarks/test_benchmark_bulk_create.py +++ b/benchmarks/test_benchmark_bulk_create.py @@ -15,7 +15,7 @@ async def make_and_insert(num_models: int): authors = [ Author( name="".join(random.sample(string.ascii_letters, 5)), - score=random.random() * 100, + score=int(random.random() * 100), ) for i in range(0, num_models) ] diff --git a/benchmarks/test_benchmark_create.py b/benchmarks/test_benchmark_create.py index 985fe2f6f..22ad00119 100644 --- a/benchmarks/test_benchmark_create.py +++ b/benchmarks/test_benchmark_create.py @@ -16,7 +16,7 @@ async def create(num_models: int): for idx in range(0, num_models): author = await Author.objects.create( name="".join(random.sample(string.ascii_letters, 5)), - score=random.random() * 100, + score=int(random.random() * 100), ) authors.append(author) return authors @@ -62,7 +62,7 @@ async def get_or_create(num_models: int): for idx in range(0, num_models): author, created = await Author.objects.get_or_create( name="".join(random.sample(string.ascii_letters, 5)), - score=random.random() * 100, + score=int(random.random() * 100), ) assert created authors.append(author) @@ -81,7 +81,7 @@ async def update_or_create(num_models: int): for idx in range(0, num_models): author = await Author.objects.update_or_create( name="".join(random.sample(string.ascii_letters, 5)), - score=random.random() * 100, + score=int(random.random() * 100), ) authors.append(author) return authors diff --git a/benchmarks/test_benchmark_init.py b/benchmarks/test_benchmark_init.py index 9a73bf11c..510ae89f2 100644 --- a/benchmarks/test_benchmark_init.py +++ b/benchmarks/test_benchmark_init.py @@ -15,13 +15,13 @@ async def initialize_models(num_models: int): authors = [ Author( name="".join(random.sample(string.ascii_letters, 5)), - score=random.random() * 100, + score=int(random.random() * 100), ) for i in range(0, num_models) ] assert len(authors) == num_models - await initialize_models(num_models) + _ = initialize_models(num_models) @pytest.mark.parametrize("num_models", [10, 20, 40]) diff --git a/benchmarks/test_benchmark_save.py b/benchmarks/test_benchmark_save.py index 333f11881..a31c72699 100644 --- a/benchmarks/test_benchmark_save.py +++ b/benchmarks/test_benchmark_save.py @@ -15,7 +15,7 @@ async def make_and_insert(num_models: int): authors = [ Author( name="".join(random.sample(string.ascii_letters, 5)), - score=random.random() * 100, + score=int(random.random() * 100), ) for i in range(0, num_models) ] diff --git a/poetry.lock b/poetry.lock index b803467ae..388bb2fb4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -219,76 +219,88 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] name = "cffi" -version = "1.16.0" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "main" -optional = true -python-versions = ">=3.8" +optional = false +python-versions = "*" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, ] [package.dependencies] @@ -629,40 +641,40 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.109.0" +version = "0.109.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.109.0-py3-none-any.whl", hash = "sha256:8c77515984cd8e8cfeb58364f8cc7a28f0692088475e2614f7bf03275eba9093"}, - {file = "fastapi-0.109.0.tar.gz", hash = "sha256:b978095b9ee01a5cf49b19f4bc1ac9b8ca83aa076e770ef8fd9af09a2b88d191"}, + {file = "fastapi-0.109.2-py3-none-any.whl", hash = "sha256:2c9bab24667293b501cad8dd388c05240c850b58ec5876ee3283c47d6e1e3a4d"}, + {file = "fastapi-0.109.2.tar.gz", hash = "sha256:f3817eac96fe4f65a2ebb4baa000f394e55f5fccdaf7f75250804bc58f354f73"}, ] [package.dependencies] pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.35.0,<0.36.0" +starlette = ">=0.36.3,<0.37.0" typing-extensions = ">=4.8.0" [package.extras] -all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" -version = "3.13.1" +version = "3.12.4" description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, + {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] +typing = ["typing-extensions (>=4.7.1)"] [[package]] name = "ghp-import" @@ -756,14 +768,14 @@ test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.39.1" +version = "0.40.0" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "griffe-0.39.1-py3-none-any.whl", hash = "sha256:6ce4ecffcf0d2f96362c5974b3f7df812da8f8d4cfcc5ebc8202ef72656fc087"}, - {file = "griffe-0.39.1.tar.gz", hash = "sha256:ead8dfede6e6531cce6bf69090a4f3c6d36fdf923c43f8e85aa530552cef0c09"}, + {file = "griffe-0.40.0-py3-none-any.whl", hash = "sha256:db1da6d1d8e08cbb20f1a7dee8c09da940540c2d4c1bfa26a9091cf6fc36a9ec"}, + {file = "griffe-0.40.0.tar.gz", hash = "sha256:76c4439eaa2737af46ae003c331ab6ca79c5365b552f7b5aed263a3b4125735b"}, ] [package.dependencies] @@ -925,72 +937,72 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.4" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, - {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] @@ -1239,21 +1251,21 @@ files = [ [[package]] name = "mysqlclient" -version = "2.2.1" +version = "2.2.3" description = "Python interface to MySQL" category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "mysqlclient-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:c5a293baebbfcfa2905545198a54e90f1cf00f211eae6637d24930abb6432cba"}, - {file = "mysqlclient-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:8f40c872f19639366e3df27bef2ff087be0e3ee0bd3453470bd29f46b54a90f6"}, - {file = "mysqlclient-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:45600f4f321096bd1ead3355bc62cfcf8d97dc78df94e4ab5db72ecb5db1bd04"}, - {file = "mysqlclient-2.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f8889cc5f0141bb307b915e981a66793df663ace92259344661084a7dd8d12a"}, - {file = "mysqlclient-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:9db6305cdf2a1da350f827d2a19be7f2666eafd9eb8d4f7cbbac5df847d61b99"}, - {file = "mysqlclient-2.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:97eee76818774bb695e018ff4c3dafaab74b9a0b0cf32c90b02caeec3b19cd8e"}, - {file = "mysqlclient-2.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4fabe1f4b545ed6244ad0ff426e6b27054b7e5c5b1392be0de2e5f2f59be0392"}, - {file = "mysqlclient-2.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:641a7c9de443ddef186a0e89f24b4251ad44f4ddc5e7094332bf2d286d7c9e33"}, - {file = "mysqlclient-2.2.1.tar.gz", hash = "sha256:2c7ad15b87293b12fd44b47c46879ec95ec647f4567e866ccd70b8337584e9b2"}, + {file = "mysqlclient-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:5a5451b3eea2a2a3316b2b432c89f25b1a28b986aa924a04aca659ad454e9a5f"}, + {file = "mysqlclient-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:2fa388cf076d3fee010d7094ca979fc8236988159c762becfea4d42cd56e6580"}, + {file = "mysqlclient-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:c37a7f641fa2e0582bf6808851dc4b82736b61ccb39e1607e59dce797db3f6c5"}, + {file = "mysqlclient-2.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:c79740385d9df70606e87dade197c5fce5c0d22c0e5c40cd048cfa693daa0e7b"}, + {file = "mysqlclient-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:7d74de2fa08dc7483b5ec82e130fde6d965f53c9ac6bf678f6d6c362c952b8b6"}, + {file = "mysqlclient-2.2.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90164463c0bda46ebe9f8ca2b7ec502ff915ab1c23af54bdf60997fc4c59e47c"}, + {file = "mysqlclient-2.2.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8b34574bceb548ac94a31c8cc1f67d454f414e5dee240dd29ad0e09405756638"}, + {file = "mysqlclient-2.2.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a47d266820fb8da26582cddc98ded1546edc7a0def556b0ca8de4a1a7dd8505c"}, + {file = "mysqlclient-2.2.3.tar.gz", hash = "sha256:ee51656e36fc5a92920b807ee8b9e373e3b0e267c89cdc95d73b1dbe46863631"}, ] [[package]] @@ -1285,62 +1297,62 @@ setuptools = "*" [[package]] name = "orjson" -version = "3.9.12" +version = "3.9.13" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "orjson-3.9.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6b4e2bed7d00753c438e83b613923afdd067564ff7ed696bfe3a7b073a236e07"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd1b8ec63f0bf54a50b498eedeccdca23bd7b658f81c524d18e410c203189365"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab8add018a53665042a5ae68200f1ad14c7953fa12110d12d41166f111724656"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12756a108875526b76e505afe6d6ba34960ac6b8c5ec2f35faf73ef161e97e07"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:890e7519c0c70296253660455f77e3a194554a3c45e42aa193cdebc76a02d82b"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d664880d7f016efbae97c725b243b33c2cbb4851ddc77f683fd1eec4a7894146"}, - {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cfdaede0fa5b500314ec7b1249c7e30e871504a57004acd116be6acdda3b8ab3"}, - {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6492ff5953011e1ba9ed1bf086835fd574bd0a3cbe252db8e15ed72a30479081"}, - {file = "orjson-3.9.12-cp310-none-win32.whl", hash = "sha256:29bf08e2eadb2c480fdc2e2daae58f2f013dff5d3b506edd1e02963b9ce9f8a9"}, - {file = "orjson-3.9.12-cp310-none-win_amd64.whl", hash = "sha256:0fc156fba60d6b50743337ba09f052d8afc8b64595112996d22f5fce01ab57da"}, - {file = "orjson-3.9.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2849f88a0a12b8d94579b67486cbd8f3a49e36a4cb3d3f0ab352c596078c730c"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3186b18754befa660b31c649a108a915493ea69b4fc33f624ed854ad3563ac65"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbbf313c9fb9d4f6cf9c22ced4b6682230457741daeb3d7060c5d06c2e73884a"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e8cd005b3926c3db9b63d264bd05e1bf4451787cc79a048f27f5190a9a0311"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59feb148392d9155f3bfed0a2a3209268e000c2c3c834fb8fe1a6af9392efcbf"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4ae815a172a1f073b05b9e04273e3b23e608a0858c4e76f606d2d75fcabde0c"}, - {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed398f9a9d5a1bf55b6e362ffc80ac846af2122d14a8243a1e6510a4eabcb71e"}, - {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d3cfb76600c5a1e6be91326b8f3b83035a370e727854a96d801c1ea08b708073"}, - {file = "orjson-3.9.12-cp311-none-win32.whl", hash = "sha256:a2b6f5252c92bcab3b742ddb3ac195c0fa74bed4319acd74f5d54d79ef4715dc"}, - {file = "orjson-3.9.12-cp311-none-win_amd64.whl", hash = "sha256:c95488e4aa1d078ff5776b58f66bd29d628fa59adcb2047f4efd3ecb2bd41a71"}, - {file = "orjson-3.9.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d6ce2062c4af43b92b0221ed4f445632c6bf4213f8a7da5396a122931377acd9"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:950951799967558c214cd6cceb7ceceed6f81d2c3c4135ee4a2c9c69f58aa225"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2dfaf71499d6fd4153f5c86eebb68e3ec1bf95851b030a4b55c7637a37bbdee4"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:659a8d7279e46c97661839035a1a218b61957316bf0202674e944ac5cfe7ed83"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af17fa87bccad0b7f6fd8ac8f9cbc9ee656b4552783b10b97a071337616db3e4"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd52dec9eddf4c8c74392f3fd52fa137b5f2e2bed1d9ae958d879de5f7d7cded"}, - {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:640e2b5d8e36b970202cfd0799d11a9a4ab46cf9212332cd642101ec952df7c8"}, - {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:daa438bd8024e03bcea2c5a92cd719a663a58e223fba967296b6ab9992259dbf"}, - {file = "orjson-3.9.12-cp312-none-win_amd64.whl", hash = "sha256:1bb8f657c39ecdb924d02e809f992c9aafeb1ad70127d53fb573a6a6ab59d549"}, - {file = "orjson-3.9.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f4098c7674901402c86ba6045a551a2ee345f9f7ed54eeffc7d86d155c8427e5"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5586a533998267458fad3a457d6f3cdbddbcce696c916599fa8e2a10a89b24d3"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54071b7398cd3f90e4bb61df46705ee96cb5e33e53fc0b2f47dbd9b000e238e1"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:67426651faa671b40443ea6f03065f9c8e22272b62fa23238b3efdacd301df31"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4a0cd56e8ee56b203abae7d482ac0d233dbfb436bb2e2d5cbcb539fe1200a312"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a84a0c3d4841a42e2571b1c1ead20a83e2792644c5827a606c50fc8af7ca4bee"}, - {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:09d60450cda3fa6c8ed17770c3a88473a16460cd0ff2ba74ef0df663b6fd3bb8"}, - {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bc82a4db9934a78ade211cf2e07161e4f068a461c1796465d10069cb50b32a80"}, - {file = "orjson-3.9.12-cp38-none-win32.whl", hash = "sha256:61563d5d3b0019804d782137a4f32c72dc44c84e7d078b89d2d2a1adbaa47b52"}, - {file = "orjson-3.9.12-cp38-none-win_amd64.whl", hash = "sha256:410f24309fbbaa2fab776e3212a81b96a1ec6037259359a32ea79fbccfcf76aa"}, - {file = "orjson-3.9.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e773f251258dd82795fd5daeac081d00b97bacf1548e44e71245543374874bcf"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b159baecfda51c840a619948c25817d37733a4d9877fea96590ef8606468b362"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:975e72e81a249174840d5a8df977d067b0183ef1560a32998be340f7e195c730"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06e42e899dde61eb1851a9fad7f1a21b8e4be063438399b63c07839b57668f6c"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c157e999e5694475a5515942aebeed6e43f7a1ed52267c1c93dcfde7d78d421"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dde1bc7c035f2d03aa49dc8642d9c6c9b1a81f2470e02055e76ed8853cfae0c3"}, - {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b0e9d73cdbdad76a53a48f563447e0e1ce34bcecef4614eb4b146383e6e7d8c9"}, - {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96e44b21fe407b8ed48afbb3721f3c8c8ce17e345fbe232bd4651ace7317782d"}, - {file = "orjson-3.9.12-cp39-none-win32.whl", hash = "sha256:cbd0f3555205bf2a60f8812133f2452d498dbefa14423ba90fe89f32276f7abf"}, - {file = "orjson-3.9.12-cp39-none-win_amd64.whl", hash = "sha256:03ea7ee7e992532c2f4a06edd7ee1553f0644790553a118e003e3c405add41fa"}, - {file = "orjson-3.9.12.tar.gz", hash = "sha256:da908d23a3b3243632b523344403b128722a5f45e278a8343c2bb67538dff0e4"}, + {file = "orjson-3.9.13-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:fa6b67f8bef277c2a4aadd548d58796854e7d760964126c3209b19bccc6a74f1"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b812417199eeb169c25f67815cfb66fd8de7ff098bf57d065e8c1943a7ba5c8f"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ccd5bd222e5041069ad9d9868ab59e6dbc53ecde8d8c82b919954fbba43b46b"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaaf80957c38e9d3f796f355a80fad945e72cd745e6b64c210e635b7043b673e"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60da7316131185d0110a1848e9ad15311e6c8938ee0b5be8cbd7261e1d80ee8f"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b98cd948372f0eb219bc309dee4633db1278687161e3280d9e693b6076951d2"}, + {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3869d65561f10071d3e7f35ae58fd377056f67d7aaed5222f318390c3ad30339"}, + {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43fd6036b16bb6742d03dae62f7bdf8214d06dea47e4353cde7e2bd1358d186f"}, + {file = "orjson-3.9.13-cp310-none-win32.whl", hash = "sha256:0d3ba9d88e20765335260d7b25547d7c571eee2b698200f97afa7d8c7cd668fc"}, + {file = "orjson-3.9.13-cp310-none-win_amd64.whl", hash = "sha256:6e47153db080f5e87e8ba638f1a8b18995eede6b0abb93964d58cf11bcea362f"}, + {file = "orjson-3.9.13-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4584e8eb727bc431baaf1bf97e35a1d8a0109c924ec847395673dfd5f4ef6d6f"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f37f0cdd026ef777a4336e599d8194c8357fc14760c2a5ddcfdf1965d45504b"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d714595d81efab11b42bccd119977d94b25d12d3a806851ff6bfd286a4bce960"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9171e8e1a1f221953e38e84ae0abffe8759002fd8968106ee379febbb5358b33"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ab9dbdec3f13f3ea6f937564ce21651844cfbf2725099f2f490426acf683c23"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811ac076855e33e931549340288e0761873baf29276ad00f221709933c644330"}, + {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:860d0f5b42d0c0afd73fa4177709f6e1b966ba691fcd72175affa902052a81d6"}, + {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:838b898e8c1f26eb6b8d81b180981273f6f5110c76c22c384979aca854194f1b"}, + {file = "orjson-3.9.13-cp311-none-win32.whl", hash = "sha256:d3222db9df629ef3c3673124f2e05fb72bc4a320c117e953fec0d69dde82e36d"}, + {file = "orjson-3.9.13-cp311-none-win_amd64.whl", hash = "sha256:978117122ca4cc59b28af5322253017f6c5fc03dbdda78c7f4b94ae984c8dd43"}, + {file = "orjson-3.9.13-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:031df1026c7ea8303332d78711f180231e3ae8b564271fb748a03926587c5546"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fd9a2101d04e85086ea6198786a3f016e45475f800712e6833e14bf9ce2832f"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:446d9ad04204e79229ae19502daeea56479e55cbc32634655d886f5a39e91b44"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b57c0954a9fdd2b05b9cec0f5a12a0bdce5bf021a5b3b09323041613972481ab"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:266e55c83f81248f63cc93d11c5e3a53df49a5d2598fa9e9db5f99837a802d5d"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31372ba3a9fe8ad118e7d22fba46bbc18e89039e3bfa89db7bc8c18ee722dca8"}, + {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3b0c4da61f39899561e08e571f54472a09fa71717d9797928af558175ae5243"}, + {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cc03a35bfc71c8ebf96ce49b82c2a7be6af4b3cd3ac34166fdb42ac510bbfff"}, + {file = "orjson-3.9.13-cp312-none-win_amd64.whl", hash = "sha256:49b7e3fe861cb246361825d1a238f2584ed8ea21e714bf6bb17cebb86772e61c"}, + {file = "orjson-3.9.13-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:62e9a99879c4d5a04926ac2518a992134bfa00d546ea5a4cae4b9be454d35a22"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d92a3e835a5100f1d5b566fff79217eab92223ca31900dba733902a182a35ab0"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23f21faf072ed3b60b5954686f98157e073f6a8068eaa58dbde83e87212eda84"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:828c502bb261588f7de897e06cb23c4b122997cb039d2014cb78e7dabe92ef0c"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16946d095212a3dec552572c5d9bca7afa40f3116ad49695a397be07d529f1fa"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3deadd8dc0e9ff844b5b656fa30a48dbee1c3b332d8278302dd9637f6b09f627"}, + {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9b1b5adc5adf596c59dca57156b71ad301d73956f5bab4039b0e34dbf50b9fa0"}, + {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ddc089315d030c54f0f03fb38286e2667c05009a78d659f108a8efcfbdf2e585"}, + {file = "orjson-3.9.13-cp38-none-win32.whl", hash = "sha256:ae77275a28667d9c82d4522b681504642055efa0368d73108511647c6499b31c"}, + {file = "orjson-3.9.13-cp38-none-win_amd64.whl", hash = "sha256:730385fdb99a21fce9bb84bb7fcbda72c88626facd74956bda712834b480729d"}, + {file = "orjson-3.9.13-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7e8e4a571d958910272af8d53a9cbe6599f9f5fd496a1bc51211183bb2072cbd"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfad553a36548262e7da0f3a7464270e13900b898800fb571a5d4b298c3f8356"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d691c44604941945b00e0a13b19a7d9c1a19511abadf0080f373e98fdeb6b31"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8c83718346de08d68b3cb1105c5d91e5fc39885d8610fdda16613d4e3941459"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ef57a53bfc2091a7cd50a640d9ae866bd7d92a5225a1bab6baa60ef62583f2"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9156b96afa38db71344522f5517077eaedf62fcd2c9148392ff93d801128809c"}, + {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31fb66b41fb2c4c817d9610f0bc7d31345728d7b5295ac78b63603407432a2b2"}, + {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8a730bf07feacb0863974e67b206b7c503a62199de1cece2eb0d4c233ec29c11"}, + {file = "orjson-3.9.13-cp39-none-win32.whl", hash = "sha256:5ef58869f3399acbbe013518d8b374ee9558659eef14bca0984f67cb1fbd3c37"}, + {file = "orjson-3.9.13-cp39-none-win_amd64.whl", hash = "sha256:9bcf56efdb83244cde070e82a69c0f03c47c235f0a5cb6c81d9da23af7fbaae4"}, + {file = "orjson-3.9.13.tar.gz", hash = "sha256:fc6bc65b0cf524ee042e0bc2912b9206ef242edfba7426cf95763e4af01f527a"}, ] [[package]] @@ -1369,19 +1381,19 @@ files = [ [[package]] name = "platformdirs" -version = "4.1.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pluggy" @@ -1500,24 +1512,12 @@ files = [ {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, ] -[[package]] -name = "py-cpuinfo" -version = "9.0.0" -description = "Get CPU info with pure Python" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, - {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, -] - [[package]] name = "pycparser" version = "2.21" description = "C parser in Python" category = "main" -optional = true +optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, @@ -1526,19 +1526,19 @@ files = [ [[package]] name = "pydantic" -version = "2.5.3" +version = "2.6.1" description = "Data validation using Python type hints" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, - {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, + {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, + {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.6" +pydantic-core = "2.16.2" typing-extensions = ">=4.6.1" [package.extras] @@ -1546,117 +1546,91 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.6" +version = "2.16.2" description = "" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, - {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, - {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, - {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, - {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, - {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, - {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, - {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, - {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, - {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, - {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, - {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, - {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, - {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, - {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, - {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, + {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, + {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, + {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, + {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, + {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, + {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, + {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, + {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, + {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, + {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, + {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, + {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, + {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, ] [package.dependencies] @@ -1774,25 +1748,27 @@ docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] [[package]] -name = "pytest-benchmark" -version = "4.0.0" -description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +name = "pytest-codspeed" +version = "2.2.0" +description = "Pytest plugin to create CodSpeed benchmarks" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-benchmark-4.0.0.tar.gz", hash = "sha256:fb0785b83efe599a6a956361c0691ae1dbb5318018561af10f3e915caa0048d1"}, - {file = "pytest_benchmark-4.0.0-py3-none-any.whl", hash = "sha256:fdb7db64e31c8b277dff9850d2a2556d8b60bcb0ea6524e36e28ffd7c87f71d6"}, + {file = "pytest_codspeed-2.2.0-py3-none-any.whl", hash = "sha256:5da48b842fc465926d122dd15bb86e86af5d9f0c53ec1b7c736e9a9aed558c13"}, + {file = "pytest_codspeed-2.2.0.tar.gz", hash = "sha256:665003fc20117b64a98d16ffd1008f5bd6bf3b1e9af142b98c00abff7f626bbd"}, ] [package.dependencies] -py-cpuinfo = "*" +cffi = ">=1.15.1,<1.16.0" +filelock = ">=3.12.2,<3.13.0" pytest = ">=3.8" +setuptools = {version = ">=67.8.0,<67.9.0", markers = "python_full_version >= \"3.12.0b1\""} [package.extras] -aspect = ["aspectlib"] -elasticsearch = ["elasticsearch"] -histogram = ["pygal", "pygaljs"] +compat = ["pytest-benchmark (>=4.0.0,<4.1.0)", "pytest-xdist (>=2.0.0,<2.1.0)"] +lint = ["black (>=23.3.0,<23.4.0)", "isort (>=5.12.0,<5.13.0)", "mypy (>=1.3.0,<1.4.0)", "ruff (>=0.0.275,<0.1.0)"] +test = ["pytest (>=7.0,<8.0)", "pytest-cov (>=4.0.0,<4.1.0)"] [[package]] name = "pytest-cov" @@ -2047,20 +2023,20 @@ files = [ [[package]] name = "setuptools" -version = "69.0.3" +version = "67.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -2163,14 +2139,14 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "starlette" -version = "0.35.1" +version = "0.36.3" description = "The little ASGI library that shines." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "starlette-0.35.1-py3-none-any.whl", hash = "sha256:50bbbda9baa098e361f398fda0928062abbaf1f54f4fadcbe17c092a01eb9a25"}, - {file = "starlette-0.35.1.tar.gz", hash = "sha256:3e2639dac3520e4f58734ed22553f950d3f3cb1001cd2eaac4d57e8cdc5f66bc"}, + {file = "starlette-0.36.3-py3-none-any.whl", hash = "sha256:13d429aa93a61dc40bf503e8c801db1f1bca3dc706b10ef2434a36123568f044"}, + {file = "starlette-0.36.3.tar.gz", hash = "sha256:90a671733cfb35771d8cc605e0b679d23b992f8dcfad48cc60b38cb29aeb7080"}, ] [package.dependencies] @@ -2178,7 +2154,7 @@ anyio = ">=3.4.0,<5" typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] [[package]] name = "tomli" @@ -2329,18 +2305,19 @@ files = [ [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.0" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2367,39 +2344,41 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "watchdog" -version = "3.0.0" +version = "4.0.0" description = "Filesystem events monitoring" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41"}, - {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397"}, - {file = "watchdog-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7"}, - {file = "watchdog-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8"}, - {file = "watchdog-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100"}, - {file = "watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"}, - {file = "watchdog-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33"}, - {file = "watchdog-3.0.0-py3-none-win32.whl", hash = "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f"}, - {file = "watchdog-3.0.0-py3-none-win_amd64.whl", hash = "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c"}, - {file = "watchdog-3.0.0-py3-none-win_ia64.whl", hash = "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759"}, - {file = "watchdog-3.0.0.tar.gz", hash = "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, + {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, + {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, + {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, + {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, + {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, + {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, + {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, ] [package.extras] @@ -2497,4 +2476,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "07ac72d838e4aba426f1b6e42c7ca4d341ffbac63c92a43075d1bcbab3296209" +content-hash = "63b5af9765f7962d631228cf29ce830475026997da61fa8187d9d531bdb00571" diff --git a/pyproject.toml b/pyproject.toml index 37a386012..0c8793883 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,13 +125,13 @@ dataclasses = { version = ">=0.6.0,<0.8 || >0.8,<1.0.0" } # Performance testing yappi = "^1.4.0" -pytest-benchmark = "^4.0.0" nest-asyncio = "^1.5.6" pre-commit = "^2.21.0" httpx = "^0.24.1" asgi-lifespan = "^2.1.0" pydantic-extra-types = "^2.5.0" +pytest-codspeed = "^2.2.0" [build-system] From 17bf9d5ae2e30299b66106ed81dc05e988993e19 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 7 Feb 2024 22:57:56 +0100 Subject: [PATCH 73/95] restore pytest-benchmark --- poetry.lock | 35 ++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 388bb2fb4..15cacb6c6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1512,6 +1512,18 @@ files = [ {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, ] +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +description = "Get CPU info with pure Python" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, + {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, +] + [[package]] name = "pycparser" version = "2.21" @@ -1747,6 +1759,27 @@ pytest = ">=7.0.0" docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] +[[package]] +name = "pytest-benchmark" +version = "4.0.0" +description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-benchmark-4.0.0.tar.gz", hash = "sha256:fb0785b83efe599a6a956361c0691ae1dbb5318018561af10f3e915caa0048d1"}, + {file = "pytest_benchmark-4.0.0-py3-none-any.whl", hash = "sha256:fdb7db64e31c8b277dff9850d2a2556d8b60bcb0ea6524e36e28ffd7c87f71d6"}, +] + +[package.dependencies] +py-cpuinfo = "*" +pytest = ">=3.8" + +[package.extras] +aspect = ["aspectlib"] +elasticsearch = ["elasticsearch"] +histogram = ["pygal", "pygaljs"] + [[package]] name = "pytest-codspeed" version = "2.2.0" @@ -2476,4 +2509,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "63b5af9765f7962d631228cf29ce830475026997da61fa8187d9d531bdb00571" +content-hash = "80dd12af8915e4112282d85cf75a4f2d14f6f051439b41344e59a122e1bfe4d0" diff --git a/pyproject.toml b/pyproject.toml index 0c8793883..6aaba248d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,6 +125,7 @@ dataclasses = { version = ">=0.6.0,<0.8 || >0.8,<1.0.0" } # Performance testing yappi = "^1.4.0" +pytest-benchmark = "^4.0.0" nest-asyncio = "^1.5.6" pre-commit = "^2.21.0" From ed47db475871c8e26554878849cc7d284e6e3752 Mon Sep 17 00:00:00 2001 From: collerek Date: Wed, 7 Feb 2024 23:03:49 +0100 Subject: [PATCH 74/95] remove codspeed --- .github/workflows/benchmark.yml | 3 + poetry.lock | 175 +++++++++++++------------------- pyproject.toml | 1 - 3 files changed, 73 insertions(+), 106 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 9aa3cb194..cca0c98d3 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -33,6 +33,9 @@ jobs: - name: Install dependencies run: poetry install --extras "all" + - name: Install codspeed + run: pip install pytest-codspeed =="2.2.0" + - name: Run benchmarks uses: CodSpeedHQ/action@v2 with: diff --git a/poetry.lock b/poetry.lock index 15cacb6c6..bc223eb3d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -231,76 +231,64 @@ files = [ [[package]] name = "cffi" -version = "1.15.1" +version = "1.16.0" description = "Foreign Function Interface for Python calling C code." category = "main" -optional = false -python-versions = "*" +optional = true +python-versions = ">=3.8" files = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] [package.dependencies] @@ -661,20 +649,20 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "filelock" -version = "3.12.4" +version = "3.13.1" description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, - {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] -typing = ["typing-extensions (>=4.7.1)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "ghp-import" @@ -1529,7 +1517,7 @@ name = "pycparser" version = "2.21" description = "C parser in Python" category = "main" -optional = false +optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, @@ -1780,29 +1768,6 @@ aspect = ["aspectlib"] elasticsearch = ["elasticsearch"] histogram = ["pygal", "pygaljs"] -[[package]] -name = "pytest-codspeed" -version = "2.2.0" -description = "Pytest plugin to create CodSpeed benchmarks" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest_codspeed-2.2.0-py3-none-any.whl", hash = "sha256:5da48b842fc465926d122dd15bb86e86af5d9f0c53ec1b7c736e9a9aed558c13"}, - {file = "pytest_codspeed-2.2.0.tar.gz", hash = "sha256:665003fc20117b64a98d16ffd1008f5bd6bf3b1e9af142b98c00abff7f626bbd"}, -] - -[package.dependencies] -cffi = ">=1.15.1,<1.16.0" -filelock = ">=3.12.2,<3.13.0" -pytest = ">=3.8" -setuptools = {version = ">=67.8.0,<67.9.0", markers = "python_full_version >= \"3.12.0b1\""} - -[package.extras] -compat = ["pytest-benchmark (>=4.0.0,<4.1.0)", "pytest-xdist (>=2.0.0,<2.1.0)"] -lint = ["black (>=23.3.0,<23.4.0)", "isort (>=5.12.0,<5.13.0)", "mypy (>=1.3.0,<1.4.0)", "ruff (>=0.0.275,<0.1.0)"] -test = ["pytest (>=7.0,<8.0)", "pytest-cov (>=4.0.0,<4.1.0)"] - [[package]] name = "pytest-cov" version = "4.1.0" @@ -2056,20 +2021,20 @@ files = [ [[package]] name = "setuptools" -version = "67.8.0" +version = "69.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, - {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -2509,4 +2474,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "80dd12af8915e4112282d85cf75a4f2d14f6f051439b41344e59a122e1bfe4d0" +content-hash = "07ac72d838e4aba426f1b6e42c7ca4d341ffbac63c92a43075d1bcbab3296209" diff --git a/pyproject.toml b/pyproject.toml index 6aaba248d..37a386012 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -132,7 +132,6 @@ pre-commit = "^2.21.0" httpx = "^0.24.1" asgi-lifespan = "^2.1.0" pydantic-extra-types = "^2.5.0" -pytest-codspeed = "^2.2.0" [build-system] From 9303ebfa03af412952228e21d920ad43fbf51e9a Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 8 Feb 2024 10:19:56 +0100 Subject: [PATCH 75/95] pin pydantic version, restore codspeed --- .github/workflows/benchmark.yml | 3 - poetry.lock | 706 +++++++++++++++++--------------- pyproject.toml | 6 +- 3 files changed, 386 insertions(+), 329 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index cca0c98d3..9aa3cb194 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -33,9 +33,6 @@ jobs: - name: Install dependencies run: poetry install --extras "all" - - name: Install codspeed - run: pip install pytest-codspeed =="2.2.0" - - name: Run benchmarks uses: CodSpeedHQ/action@v2 with: diff --git a/poetry.lock b/poetry.lock index bc223eb3d..6c98a6979 100644 --- a/poetry.lock +++ b/poetry.lock @@ -219,76 +219,88 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, ] [[package]] name = "cffi" -version = "1.16.0" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "main" -optional = true -python-versions = ">=3.8" +optional = false +python-versions = "*" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, ] [package.dependencies] @@ -649,20 +661,20 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "filelock" -version = "3.13.1" +version = "3.12.4" description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, + {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] +typing = ["typing-extensions (>=4.7.1)"] [[package]] name = "ghp-import" @@ -756,14 +768,14 @@ test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.40.0" +version = "0.39.1" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "griffe-0.40.0-py3-none-any.whl", hash = "sha256:db1da6d1d8e08cbb20f1a7dee8c09da940540c2d4c1bfa26a9091cf6fc36a9ec"}, - {file = "griffe-0.40.0.tar.gz", hash = "sha256:76c4439eaa2737af46ae003c331ab6ca79c5365b552f7b5aed263a3b4125735b"}, + {file = "griffe-0.39.1-py3-none-any.whl", hash = "sha256:6ce4ecffcf0d2f96362c5974b3f7df812da8f8d4cfcc5ebc8202ef72656fc087"}, + {file = "griffe-0.39.1.tar.gz", hash = "sha256:ead8dfede6e6531cce6bf69090a4f3c6d36fdf923c43f8e85aa530552cef0c09"}, ] [package.dependencies] @@ -925,72 +937,72 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.5" +version = "2.1.4" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, + {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, ] [[package]] @@ -1239,21 +1251,21 @@ files = [ [[package]] name = "mysqlclient" -version = "2.2.3" +version = "2.2.1" description = "Python interface to MySQL" category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "mysqlclient-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:5a5451b3eea2a2a3316b2b432c89f25b1a28b986aa924a04aca659ad454e9a5f"}, - {file = "mysqlclient-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:2fa388cf076d3fee010d7094ca979fc8236988159c762becfea4d42cd56e6580"}, - {file = "mysqlclient-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:c37a7f641fa2e0582bf6808851dc4b82736b61ccb39e1607e59dce797db3f6c5"}, - {file = "mysqlclient-2.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:c79740385d9df70606e87dade197c5fce5c0d22c0e5c40cd048cfa693daa0e7b"}, - {file = "mysqlclient-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:7d74de2fa08dc7483b5ec82e130fde6d965f53c9ac6bf678f6d6c362c952b8b6"}, - {file = "mysqlclient-2.2.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90164463c0bda46ebe9f8ca2b7ec502ff915ab1c23af54bdf60997fc4c59e47c"}, - {file = "mysqlclient-2.2.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8b34574bceb548ac94a31c8cc1f67d454f414e5dee240dd29ad0e09405756638"}, - {file = "mysqlclient-2.2.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a47d266820fb8da26582cddc98ded1546edc7a0def556b0ca8de4a1a7dd8505c"}, - {file = "mysqlclient-2.2.3.tar.gz", hash = "sha256:ee51656e36fc5a92920b807ee8b9e373e3b0e267c89cdc95d73b1dbe46863631"}, + {file = "mysqlclient-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:c5a293baebbfcfa2905545198a54e90f1cf00f211eae6637d24930abb6432cba"}, + {file = "mysqlclient-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:8f40c872f19639366e3df27bef2ff087be0e3ee0bd3453470bd29f46b54a90f6"}, + {file = "mysqlclient-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:45600f4f321096bd1ead3355bc62cfcf8d97dc78df94e4ab5db72ecb5db1bd04"}, + {file = "mysqlclient-2.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f8889cc5f0141bb307b915e981a66793df663ace92259344661084a7dd8d12a"}, + {file = "mysqlclient-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:9db6305cdf2a1da350f827d2a19be7f2666eafd9eb8d4f7cbbac5df847d61b99"}, + {file = "mysqlclient-2.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:97eee76818774bb695e018ff4c3dafaab74b9a0b0cf32c90b02caeec3b19cd8e"}, + {file = "mysqlclient-2.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4fabe1f4b545ed6244ad0ff426e6b27054b7e5c5b1392be0de2e5f2f59be0392"}, + {file = "mysqlclient-2.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:641a7c9de443ddef186a0e89f24b4251ad44f4ddc5e7094332bf2d286d7c9e33"}, + {file = "mysqlclient-2.2.1.tar.gz", hash = "sha256:2c7ad15b87293b12fd44b47c46879ec95ec647f4567e866ccd70b8337584e9b2"}, ] [[package]] @@ -1285,62 +1297,62 @@ setuptools = "*" [[package]] name = "orjson" -version = "3.9.13" +version = "3.9.12" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "orjson-3.9.13-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:fa6b67f8bef277c2a4aadd548d58796854e7d760964126c3209b19bccc6a74f1"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b812417199eeb169c25f67815cfb66fd8de7ff098bf57d065e8c1943a7ba5c8f"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ccd5bd222e5041069ad9d9868ab59e6dbc53ecde8d8c82b919954fbba43b46b"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaaf80957c38e9d3f796f355a80fad945e72cd745e6b64c210e635b7043b673e"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60da7316131185d0110a1848e9ad15311e6c8938ee0b5be8cbd7261e1d80ee8f"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b98cd948372f0eb219bc309dee4633db1278687161e3280d9e693b6076951d2"}, - {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3869d65561f10071d3e7f35ae58fd377056f67d7aaed5222f318390c3ad30339"}, - {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43fd6036b16bb6742d03dae62f7bdf8214d06dea47e4353cde7e2bd1358d186f"}, - {file = "orjson-3.9.13-cp310-none-win32.whl", hash = "sha256:0d3ba9d88e20765335260d7b25547d7c571eee2b698200f97afa7d8c7cd668fc"}, - {file = "orjson-3.9.13-cp310-none-win_amd64.whl", hash = "sha256:6e47153db080f5e87e8ba638f1a8b18995eede6b0abb93964d58cf11bcea362f"}, - {file = "orjson-3.9.13-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4584e8eb727bc431baaf1bf97e35a1d8a0109c924ec847395673dfd5f4ef6d6f"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f37f0cdd026ef777a4336e599d8194c8357fc14760c2a5ddcfdf1965d45504b"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d714595d81efab11b42bccd119977d94b25d12d3a806851ff6bfd286a4bce960"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9171e8e1a1f221953e38e84ae0abffe8759002fd8968106ee379febbb5358b33"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ab9dbdec3f13f3ea6f937564ce21651844cfbf2725099f2f490426acf683c23"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811ac076855e33e931549340288e0761873baf29276ad00f221709933c644330"}, - {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:860d0f5b42d0c0afd73fa4177709f6e1b966ba691fcd72175affa902052a81d6"}, - {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:838b898e8c1f26eb6b8d81b180981273f6f5110c76c22c384979aca854194f1b"}, - {file = "orjson-3.9.13-cp311-none-win32.whl", hash = "sha256:d3222db9df629ef3c3673124f2e05fb72bc4a320c117e953fec0d69dde82e36d"}, - {file = "orjson-3.9.13-cp311-none-win_amd64.whl", hash = "sha256:978117122ca4cc59b28af5322253017f6c5fc03dbdda78c7f4b94ae984c8dd43"}, - {file = "orjson-3.9.13-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:031df1026c7ea8303332d78711f180231e3ae8b564271fb748a03926587c5546"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fd9a2101d04e85086ea6198786a3f016e45475f800712e6833e14bf9ce2832f"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:446d9ad04204e79229ae19502daeea56479e55cbc32634655d886f5a39e91b44"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b57c0954a9fdd2b05b9cec0f5a12a0bdce5bf021a5b3b09323041613972481ab"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:266e55c83f81248f63cc93d11c5e3a53df49a5d2598fa9e9db5f99837a802d5d"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31372ba3a9fe8ad118e7d22fba46bbc18e89039e3bfa89db7bc8c18ee722dca8"}, - {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3b0c4da61f39899561e08e571f54472a09fa71717d9797928af558175ae5243"}, - {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cc03a35bfc71c8ebf96ce49b82c2a7be6af4b3cd3ac34166fdb42ac510bbfff"}, - {file = "orjson-3.9.13-cp312-none-win_amd64.whl", hash = "sha256:49b7e3fe861cb246361825d1a238f2584ed8ea21e714bf6bb17cebb86772e61c"}, - {file = "orjson-3.9.13-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:62e9a99879c4d5a04926ac2518a992134bfa00d546ea5a4cae4b9be454d35a22"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d92a3e835a5100f1d5b566fff79217eab92223ca31900dba733902a182a35ab0"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23f21faf072ed3b60b5954686f98157e073f6a8068eaa58dbde83e87212eda84"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:828c502bb261588f7de897e06cb23c4b122997cb039d2014cb78e7dabe92ef0c"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16946d095212a3dec552572c5d9bca7afa40f3116ad49695a397be07d529f1fa"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3deadd8dc0e9ff844b5b656fa30a48dbee1c3b332d8278302dd9637f6b09f627"}, - {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9b1b5adc5adf596c59dca57156b71ad301d73956f5bab4039b0e34dbf50b9fa0"}, - {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ddc089315d030c54f0f03fb38286e2667c05009a78d659f108a8efcfbdf2e585"}, - {file = "orjson-3.9.13-cp38-none-win32.whl", hash = "sha256:ae77275a28667d9c82d4522b681504642055efa0368d73108511647c6499b31c"}, - {file = "orjson-3.9.13-cp38-none-win_amd64.whl", hash = "sha256:730385fdb99a21fce9bb84bb7fcbda72c88626facd74956bda712834b480729d"}, - {file = "orjson-3.9.13-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7e8e4a571d958910272af8d53a9cbe6599f9f5fd496a1bc51211183bb2072cbd"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfad553a36548262e7da0f3a7464270e13900b898800fb571a5d4b298c3f8356"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d691c44604941945b00e0a13b19a7d9c1a19511abadf0080f373e98fdeb6b31"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8c83718346de08d68b3cb1105c5d91e5fc39885d8610fdda16613d4e3941459"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ef57a53bfc2091a7cd50a640d9ae866bd7d92a5225a1bab6baa60ef62583f2"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9156b96afa38db71344522f5517077eaedf62fcd2c9148392ff93d801128809c"}, - {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31fb66b41fb2c4c817d9610f0bc7d31345728d7b5295ac78b63603407432a2b2"}, - {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8a730bf07feacb0863974e67b206b7c503a62199de1cece2eb0d4c233ec29c11"}, - {file = "orjson-3.9.13-cp39-none-win32.whl", hash = "sha256:5ef58869f3399acbbe013518d8b374ee9558659eef14bca0984f67cb1fbd3c37"}, - {file = "orjson-3.9.13-cp39-none-win_amd64.whl", hash = "sha256:9bcf56efdb83244cde070e82a69c0f03c47c235f0a5cb6c81d9da23af7fbaae4"}, - {file = "orjson-3.9.13.tar.gz", hash = "sha256:fc6bc65b0cf524ee042e0bc2912b9206ef242edfba7426cf95763e4af01f527a"}, + {file = "orjson-3.9.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6b4e2bed7d00753c438e83b613923afdd067564ff7ed696bfe3a7b073a236e07"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd1b8ec63f0bf54a50b498eedeccdca23bd7b658f81c524d18e410c203189365"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab8add018a53665042a5ae68200f1ad14c7953fa12110d12d41166f111724656"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12756a108875526b76e505afe6d6ba34960ac6b8c5ec2f35faf73ef161e97e07"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:890e7519c0c70296253660455f77e3a194554a3c45e42aa193cdebc76a02d82b"}, + {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d664880d7f016efbae97c725b243b33c2cbb4851ddc77f683fd1eec4a7894146"}, + {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cfdaede0fa5b500314ec7b1249c7e30e871504a57004acd116be6acdda3b8ab3"}, + {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6492ff5953011e1ba9ed1bf086835fd574bd0a3cbe252db8e15ed72a30479081"}, + {file = "orjson-3.9.12-cp310-none-win32.whl", hash = "sha256:29bf08e2eadb2c480fdc2e2daae58f2f013dff5d3b506edd1e02963b9ce9f8a9"}, + {file = "orjson-3.9.12-cp310-none-win_amd64.whl", hash = "sha256:0fc156fba60d6b50743337ba09f052d8afc8b64595112996d22f5fce01ab57da"}, + {file = "orjson-3.9.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2849f88a0a12b8d94579b67486cbd8f3a49e36a4cb3d3f0ab352c596078c730c"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3186b18754befa660b31c649a108a915493ea69b4fc33f624ed854ad3563ac65"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbbf313c9fb9d4f6cf9c22ced4b6682230457741daeb3d7060c5d06c2e73884a"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e8cd005b3926c3db9b63d264bd05e1bf4451787cc79a048f27f5190a9a0311"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59feb148392d9155f3bfed0a2a3209268e000c2c3c834fb8fe1a6af9392efcbf"}, + {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4ae815a172a1f073b05b9e04273e3b23e608a0858c4e76f606d2d75fcabde0c"}, + {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed398f9a9d5a1bf55b6e362ffc80ac846af2122d14a8243a1e6510a4eabcb71e"}, + {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d3cfb76600c5a1e6be91326b8f3b83035a370e727854a96d801c1ea08b708073"}, + {file = "orjson-3.9.12-cp311-none-win32.whl", hash = "sha256:a2b6f5252c92bcab3b742ddb3ac195c0fa74bed4319acd74f5d54d79ef4715dc"}, + {file = "orjson-3.9.12-cp311-none-win_amd64.whl", hash = "sha256:c95488e4aa1d078ff5776b58f66bd29d628fa59adcb2047f4efd3ecb2bd41a71"}, + {file = "orjson-3.9.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d6ce2062c4af43b92b0221ed4f445632c6bf4213f8a7da5396a122931377acd9"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:950951799967558c214cd6cceb7ceceed6f81d2c3c4135ee4a2c9c69f58aa225"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2dfaf71499d6fd4153f5c86eebb68e3ec1bf95851b030a4b55c7637a37bbdee4"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:659a8d7279e46c97661839035a1a218b61957316bf0202674e944ac5cfe7ed83"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af17fa87bccad0b7f6fd8ac8f9cbc9ee656b4552783b10b97a071337616db3e4"}, + {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd52dec9eddf4c8c74392f3fd52fa137b5f2e2bed1d9ae958d879de5f7d7cded"}, + {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:640e2b5d8e36b970202cfd0799d11a9a4ab46cf9212332cd642101ec952df7c8"}, + {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:daa438bd8024e03bcea2c5a92cd719a663a58e223fba967296b6ab9992259dbf"}, + {file = "orjson-3.9.12-cp312-none-win_amd64.whl", hash = "sha256:1bb8f657c39ecdb924d02e809f992c9aafeb1ad70127d53fb573a6a6ab59d549"}, + {file = "orjson-3.9.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f4098c7674901402c86ba6045a551a2ee345f9f7ed54eeffc7d86d155c8427e5"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5586a533998267458fad3a457d6f3cdbddbcce696c916599fa8e2a10a89b24d3"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54071b7398cd3f90e4bb61df46705ee96cb5e33e53fc0b2f47dbd9b000e238e1"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:67426651faa671b40443ea6f03065f9c8e22272b62fa23238b3efdacd301df31"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4a0cd56e8ee56b203abae7d482ac0d233dbfb436bb2e2d5cbcb539fe1200a312"}, + {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a84a0c3d4841a42e2571b1c1ead20a83e2792644c5827a606c50fc8af7ca4bee"}, + {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:09d60450cda3fa6c8ed17770c3a88473a16460cd0ff2ba74ef0df663b6fd3bb8"}, + {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bc82a4db9934a78ade211cf2e07161e4f068a461c1796465d10069cb50b32a80"}, + {file = "orjson-3.9.12-cp38-none-win32.whl", hash = "sha256:61563d5d3b0019804d782137a4f32c72dc44c84e7d078b89d2d2a1adbaa47b52"}, + {file = "orjson-3.9.12-cp38-none-win_amd64.whl", hash = "sha256:410f24309fbbaa2fab776e3212a81b96a1ec6037259359a32ea79fbccfcf76aa"}, + {file = "orjson-3.9.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e773f251258dd82795fd5daeac081d00b97bacf1548e44e71245543374874bcf"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b159baecfda51c840a619948c25817d37733a4d9877fea96590ef8606468b362"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:975e72e81a249174840d5a8df977d067b0183ef1560a32998be340f7e195c730"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06e42e899dde61eb1851a9fad7f1a21b8e4be063438399b63c07839b57668f6c"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c157e999e5694475a5515942aebeed6e43f7a1ed52267c1c93dcfde7d78d421"}, + {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dde1bc7c035f2d03aa49dc8642d9c6c9b1a81f2470e02055e76ed8853cfae0c3"}, + {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b0e9d73cdbdad76a53a48f563447e0e1ce34bcecef4614eb4b146383e6e7d8c9"}, + {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96e44b21fe407b8ed48afbb3721f3c8c8ce17e345fbe232bd4651ace7317782d"}, + {file = "orjson-3.9.12-cp39-none-win32.whl", hash = "sha256:cbd0f3555205bf2a60f8812133f2452d498dbefa14423ba90fe89f32276f7abf"}, + {file = "orjson-3.9.12-cp39-none-win_amd64.whl", hash = "sha256:03ea7ee7e992532c2f4a06edd7ee1553f0644790553a118e003e3c405add41fa"}, + {file = "orjson-3.9.12.tar.gz", hash = "sha256:da908d23a3b3243632b523344403b128722a5f45e278a8343c2bb67538dff0e4"}, ] [[package]] @@ -1369,19 +1381,19 @@ files = [ [[package]] name = "platformdirs" -version = "4.2.0" +version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, - {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" @@ -1517,7 +1529,7 @@ name = "pycparser" version = "2.21" description = "C parser in Python" category = "main" -optional = true +optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, @@ -1526,19 +1538,19 @@ files = [ [[package]] name = "pydantic" -version = "2.6.1" +version = "2.5.3" description = "Data validation using Python type hints" category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, - {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, + {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, + {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.16.2" +pydantic-core = "2.14.6" typing-extensions = ">=4.6.1" [package.extras] @@ -1546,91 +1558,117 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.16.2" +version = "2.14.6" description = "" category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, - {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, - {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, - {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, - {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, - {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, - {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, - {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, - {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, - {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, - {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, - {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, - {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, - {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, + {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, + {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, + {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, + {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, + {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, + {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, + {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, + {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, + {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, + {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, + {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, + {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, + {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, + {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, + {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, + {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, + {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, + {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, + {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, + {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, + {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, + {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, + {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, + {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, + {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, + {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, + {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, + {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, + {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, + {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, + {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, + {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, + {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, + {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, + {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, ] [package.dependencies] @@ -1768,6 +1806,29 @@ aspect = ["aspectlib"] elasticsearch = ["elasticsearch"] histogram = ["pygal", "pygaljs"] +[[package]] +name = "pytest-codspeed" +version = "2.2.0" +description = "Pytest plugin to create CodSpeed benchmarks" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest_codspeed-2.2.0-py3-none-any.whl", hash = "sha256:5da48b842fc465926d122dd15bb86e86af5d9f0c53ec1b7c736e9a9aed558c13"}, + {file = "pytest_codspeed-2.2.0.tar.gz", hash = "sha256:665003fc20117b64a98d16ffd1008f5bd6bf3b1e9af142b98c00abff7f626bbd"}, +] + +[package.dependencies] +cffi = ">=1.15.1,<1.16.0" +filelock = ">=3.12.2,<3.13.0" +pytest = ">=3.8" +setuptools = {version = ">=67.8.0,<67.9.0", markers = "python_full_version >= \"3.12.0b1\""} + +[package.extras] +compat = ["pytest-benchmark (>=4.0.0,<4.1.0)", "pytest-xdist (>=2.0.0,<2.1.0)"] +lint = ["black (>=23.3.0,<23.4.0)", "isort (>=5.12.0,<5.13.0)", "mypy (>=1.3.0,<1.4.0)", "ruff (>=0.0.275,<0.1.0)"] +test = ["pytest (>=7.0,<8.0)", "pytest-cov (>=4.0.0,<4.1.0)"] + [[package]] name = "pytest-cov" version = "4.1.0" @@ -2021,20 +2082,20 @@ files = [ [[package]] name = "setuptools" -version = "69.0.3" +version = "67.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -2303,19 +2364,18 @@ files = [ [[package]] name = "urllib3" -version = "2.2.0" +version = "2.1.0" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, - {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2342,41 +2402,39 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "watchdog" -version = "4.0.0" +version = "3.0.0" description = "Filesystem events monitoring" category = "dev" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, - {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, - {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, - {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, - {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, - {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, - {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, - {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, + {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41"}, + {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397"}, + {file = "watchdog-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7"}, + {file = "watchdog-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8"}, + {file = "watchdog-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100"}, + {file = "watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"}, + {file = "watchdog-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33"}, + {file = "watchdog-3.0.0-py3-none-win32.whl", hash = "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f"}, + {file = "watchdog-3.0.0-py3-none-win_amd64.whl", hash = "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c"}, + {file = "watchdog-3.0.0-py3-none-win_ia64.whl", hash = "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759"}, + {file = "watchdog-3.0.0.tar.gz", hash = "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9"}, ] [package.extras] @@ -2474,4 +2532,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "07ac72d838e4aba426f1b6e42c7ca4d341ffbac63c92a43075d1bcbab3296209" +content-hash = "06f58f984c8b43abf1acc398d2c5eb20fcc29f7c52268f81560d2728f029e797" diff --git a/pyproject.toml b/pyproject.toml index 37a386012..48b8cc79c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.8.0" databases = ">=0.3.2,!=0.5.0,!=0.5.1,!=0.5.2,!=0.5.3,<0.6.3" -pydantic = ">=v2.5.3" +pydantic = "v2.5.3" SQLAlchemy = ">=1.3.18,<1.4.42" cryptography = { version = ">=35,<42", optional = true } # Async database drivers @@ -95,7 +95,7 @@ pytest = "^7.4.0" pytest-cov = "^4.0.0" codecov = "^2.1.13" pytest-asyncio = "^0.21.0" -fastapi = ">=0.105.0" +fastapi = "^0.109.1" black = "^24.1.0" ruff = "^0.0.275" @@ -132,6 +132,8 @@ pre-commit = "^2.21.0" httpx = "^0.24.1" asgi-lifespan = "^2.1.0" pydantic-extra-types = "^2.5.0" +watchdog = "<4.0.0" +pytest-codspeed = "^2.2.0" [build-system] From 851f1f14ca09b60956e1693f8a7ec1b694d3d5a9 Mon Sep 17 00:00:00 2001 From: collerek Date: Thu, 8 Feb 2024 10:35:52 +0100 Subject: [PATCH 76/95] change on push to pydantic_v2 to trigger first one --- .github/workflows/benchmark.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 9aa3cb194..4c7095a16 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -2,8 +2,7 @@ name: codspeed-benchmarks on: push: - branches: - - "master" # or "master" + branches: [ master, pydantic_v2 ] pull_request: branches: [ master, pydantic_v2 ] # `workflow_dispatch` allows CodSpeed to trigger backtest From 27d798cd39468fd78bcbd5e2f9ba7a9259afca8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Goran=20Meki=C4=87?= Date: Sun, 11 Feb 2024 18:49:42 +0100 Subject: [PATCH 77/95] Use lifespan function instead of event (#1259) --- .github/workflows/test-package.yml | 26 ++- benchmarks/conftest.py | 24 +-- docs/fastapi/index.md | 45 ++--- docs_src/fastapi/docs001.py | 32 +--- examples/fastapi_quick_start.py | 21 +-- ormar/models/ormar_config.py | 4 + tests/lifespan.py | 33 ++++ tests/settings.py | 14 ++ .../test_deferred/test_forward_cross_refs.py | 30 +--- tests/test_deferred/test_forward_refs.py | 81 +++------ .../test_more_same_table_joins.py | 53 ++---- tests/test_deferred/test_same_table_joins.py | 59 ++----- .../test_encryption/test_encrypted_columns.py | 30 +--- .../test_complex_relation_tree_performance.py | 22 +-- .../test_dumping_model_to_dict.py | 16 +- .../test_excludable_items.py | 17 +- .../test_excluding_fields_in_fastapi.py | 47 +---- .../test_excluding_fields_with_default.py | 33 +--- .../test_excluding_subset_of_columns.py | 37 ++-- .../test_pydantic_dict_params.py | 34 ++-- tests/test_fastapi/test_binary_fields.py | 41 +---- ...est_docs_with_multiple_relations_to_one.py | 17 +- tests/test_fastapi/test_enum_schema.py | 18 +- .../test_excludes_with_get_pydantic.py | 56 +++--- tests/test_fastapi/test_excluding_fields.py | 45 +---- .../test_extra_ignore_parameter.py | 39 +---- tests/test_fastapi/test_fastapi_docs.py | 38 +--- tests/test_fastapi/test_fastapi_usage.py | 26 ++- .../test_inheritance_concrete_fastapi.py | 162 ++++++++++++++---- .../test_inheritance_mixins_fastapi.py | 63 +++---- tests/test_fastapi/test_json_field_fastapi.py | 44 +---- tests/test_fastapi/test_m2m_forwardref.py | 39 +---- .../test_more_reallife_fastapi.py | 44 +---- tests/test_fastapi/test_nested_saving.py | 52 ++---- tests/test_fastapi/test_recursion_error.py | 52 +----- .../test_relations_with_nested_defaults.py | 40 +---- .../test_schema_not_allowed_params.py | 13 +- .../test_fastapi/test_skip_reverse_models.py | 39 +---- tests/test_fastapi/test_wekref_exclusion.py | 44 +---- ...est_excluding_parent_fields_inheritance.py | 51 ++---- .../test_geting_pydantic_models.py | 14 +- .../test_inheritance_concrete.py | 98 ++++------- .../test_inheritance_mixins.py | 46 ++--- .../test_inheritance_of_property_fields.py | 31 +--- .../test_inheritance_with_default.py | 23 +-- ...erited_class_is_not_abstract_by_default.py | 27 +-- .../test_nested_models_pydantic.py | 16 +- .../test_pydantic_fields_order.py | 27 +-- .../test_validators_are_inherited.py | 18 +- .../test_validators_in_generated_pydantic.py | 22 +-- .../test_check_constraints.py | 25 +-- .../test_index_constraints.py | 25 +-- .../test_unique_constraints.py | 25 +-- tests/test_model_definition/test_aliases.py | 45 ++--- tests/test_model_definition/test_columns.py | 42 ++--- .../test_create_uses_init_for_consistency.py | 22 +-- .../test_dates_with_timezone.py | 51 ++---- .../test_equality_and_hash.py | 29 +--- .../test_extra_ignore_parameter.py | 16 +- .../test_fields_access.py | 23 +-- ...oreign_key_value_used_for_related_model.py | 28 +-- tests/test_model_definition/test_iterate.py | 87 ++++------ .../test_model_construct.py | 53 ++---- .../test_model_definition.py | 59 ++----- tests/test_model_definition/test_models.py | 158 ++++++----------- .../test_models_are_pickable.py | 31 +--- .../test_overwriting_pydantic_field_type.py | 25 +-- .../test_overwriting_sql_nullable.py | 24 +-- .../test_pk_field_is_always_not_null.py | 16 +- .../test_model_definition/test_properties.py | 25 +-- .../test_pydantic_fields.py | 26 +-- .../test_pydantic_only_fields.py | 27 +-- .../test_pydantic_private_attributes.py | 16 +- .../test_model_definition/test_save_status.py | 73 +++----- .../test_saving_nullable_fields.py | 33 +--- .../test_server_default.py | 27 +-- .../test_setting_comments_in_db.py | 21 +-- .../test_excludes_in_load_all.py | 25 +-- tests/test_model_methods/test_load_all.py | 41 ++--- .../test_populate_default_values.py | 18 +- tests/test_model_methods/test_save_related.py | 61 ++----- .../test_save_related_from_dict.py | 77 +++------ .../test_save_related_uuid.py | 32 +--- tests/test_model_methods/test_update.py | 31 +--- tests/test_model_methods/test_upsert.py | 29 +--- .../test_ordering/test_default_model_order.py | 29 +--- .../test_default_relation_order.py | 31 +--- .../test_default_through_relation_order.py | 25 +-- .../test_proper_order_of_sorting_apply.py | 25 +-- tests/test_queries/test_adding_related.py | 29 +--- tests/test_queries/test_aggr_functions.py | 35 ++-- .../test_deep_relations_select_all.py | 81 ++------- tests/test_queries/test_filter_groups.py | 16 +- .../test_indirect_relations_to_self.py | 31 +--- tests/test_queries/test_isnull_filter.py | 31 +--- .../test_nested_reverse_relations.py | 22 +-- .../test_non_relation_fields_not_merged.py | 23 +-- tests/test_queries/test_or_filters.py | 23 +-- tests/test_queries/test_order_by.py | 73 ++------ tests/test_queries/test_pagination.py | 37 ++-- .../test_queryproxy_on_m2m_models.py | 54 ++---- .../test_queryset_level_methods.py | 91 ++++------ ...t_quoting_table_names_in_on_join_clause.py | 37 +--- .../test_reserved_sql_keywords_escaped.py | 25 +-- .../test_queries/test_reverse_fk_queryset.py | 55 ++---- .../test_selecting_subset_of_columns.py | 55 ++---- .../test_values_and_values_list.py | 54 +++--- tests/test_relations/test_cascades.py | 57 ++---- ...ustomizing_through_model_relation_names.py | 31 +--- .../test_database_fk_creation.py | 49 ++---- tests/test_relations/test_foreign_keys.py | 105 ++++-------- .../test_relations/test_m2m_through_fields.py | 47 ++--- tests/test_relations/test_many_to_many.py | 54 ++---- ...est_postgress_select_related_with_limit.py | 25 +-- tests/test_relations/test_prefetch_related.py | 85 +++------ ...efetch_related_multiple_models_relation.py | 37 +--- .../test_python_style_relations.py | 38 ++-- .../test_relations_default_exception.py | 36 ++-- .../test_replacing_models_with_copy.py | 29 +--- tests/test_relations/test_saving_related.py | 37 ++-- .../test_select_related_with_limit.py | 43 ++--- ...select_related_with_m2m_and_pk_name_set.py | 22 +-- .../test_selecting_proper_table_prefix.py | 37 +--- tests/test_relations/test_skipping_reverse.py | 30 +--- .../test_through_relations_fail.py | 17 +- tests/test_relations/test_weakref_checking.py | 24 +-- tests/test_signals/test_signals.py | 65 +++---- .../test_signals_for_relations.py | 47 ++--- tests/test_utils/test_queryset_utils.py | 20 +-- 129 files changed, 1596 insertions(+), 3470 deletions(-) create mode 100644 tests/lifespan.py diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 8f1d7bdc1..9456a4300 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -39,7 +39,7 @@ jobs: POSTGRES_DB: testsuite ports: - 5432:5432 - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 --name postgres steps: - name: Checkout @@ -71,6 +71,30 @@ jobs: DATABASE_URL: "mysql://username:password@127.0.0.1:3306/testsuite" run: bash scripts/test.sh + - name: Install postgresql-client + run: | + sudo apt-get update + sudo apt-get install --yes postgresql-client + + - name: Connect to PostgreSQL with CLI + run: env PGPASSWORD=password psql -h localhost -U username -c 'SELECT VERSION();' testsuite + + - name: Show max connections + run: env PGPASSWORD=password psql -h localhost -U username -c 'SHOW max_connections;' testsuite + + - name: Alter max connections + run: | + + docker exec -i postgres bash << EOF + sed -i -e 's/max_connections = 100/max_connections = 1000/' /var/lib/postgresql/data/postgresql.conf + sed -i -e 's/shared_buffers = 128MB/shared_buffers = 512MB/' /var/lib/postgresql/data/postgresql.conf + EOF + docker restart --time 0 postgres + sleep 5 + + - name: Show max connections + run: env PGPASSWORD=password psql -h localhost -U username -c 'SHOW max_connections;' testsuite + - name: Run postgres env: DATABASE_URL: "postgresql://username:password@localhost:5432/testsuite" diff --git a/benchmarks/conftest.py b/benchmarks/conftest.py index 99cb8438e..083ab4c5c 100644 --- a/benchmarks/conftest.py +++ b/benchmarks/conftest.py @@ -3,28 +3,20 @@ import string import time -import databases import nest_asyncio import ormar import pytest import pytest_asyncio -import sqlalchemy -from tests.settings import DATABASE_URL -nest_asyncio.apply() +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() +base_ormar_config = create_config() +nest_asyncio.apply() pytestmark = pytest.mark.asyncio -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) - - class Author(ormar.Model): ormar_config = base_ormar_config.copy(tablename="authors") @@ -57,13 +49,7 @@ class Book(ormar.Model): year: int = ormar.Integer(nullable=True) -@pytest.fixture(autouse=True, scope="function") # TODO: fix this to be module -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config, scope="function") @pytest_asyncio.fixture diff --git a/docs/fastapi/index.md b/docs/fastapi/index.md index fe5b8abd3..25521a73c 100644 --- a/docs/fastapi/index.md +++ b/docs/fastapi/index.md @@ -26,7 +26,8 @@ Here you can find a very simple sample application code. ### Imports and initialization -First take care of the imports and initialization +Define startup and shutdown procedures using FastAPI lifespan and use is in the +application. ```python from typing import List, Optional @@ -36,29 +37,29 @@ from fastapi import FastAPI import ormar -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database("sqlite:///test.db") -app.state.database = database -``` +from contextlib import asynccontextmanager +from fastapi import FastAPI -### Database connection -Next define startup and shutdown events (or use middleware) -- note that this is `databases` specific setting not the ormar one -```python -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() +@asynccontextmanager +async def lifespan(_: FastAPI) -> AsyncIterator[None]: + if not config.database.is_connected: + await config.database.connect() + config.metadata.drop_all(config.engine) + config.metadata.create_all(config.engine) + + yield + + if config.database.is_connected: + config.metadata.drop_all(config.engine) + await config.database.disconnect() + + +base_ormar_config = ormar.OrmarConfig( + metadata=sqlalchemy.MetaData(), + database=databases.Database("sqlite:///test.db"), +) +app = FastAPI(lifespan=lifespan(base_ormar_config)) ``` !!!info diff --git a/docs_src/fastapi/docs001.py b/docs_src/fastapi/docs001.py index b19912691..68ee72dba 100644 --- a/docs_src/fastapi/docs001.py +++ b/docs_src/fastapi/docs001.py @@ -1,45 +1,25 @@ from typing import List, Optional -import databases import ormar -import sqlalchemy from fastapi import FastAPI -DATABASE_URL = "sqlite:///test.db" +from tests.settings import create_config +from tests.lifespan import lifespan -ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() -) -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database("sqlite:///test.db") -app.state.database = database - - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class Category(ormar.Model): - ormar_config = ormar_base_config.copy(tablename="categories") + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - ormar_config = ormar_base_config.copy(tablename="items") + ormar_config = base_ormar_config.copy(tablename="items") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/examples/fastapi_quick_start.py b/examples/fastapi_quick_start.py index 8757cfb04..5883b8e8a 100644 --- a/examples/fastapi_quick_start.py +++ b/examples/fastapi_quick_start.py @@ -1,3 +1,4 @@ +from contextlib import asynccontextmanager from typing import List, Optional import databases @@ -13,25 +14,21 @@ ) -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database("sqlite:///test.db") -app.state.database = database - - -@app.on_event("startup") -async def startup() -> None: +@asynccontextmanager +async def lifespan(app: FastAPI): database_ = app.state.database if not database_.is_connected: await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: + yield database_ = app.state.database if database_.is_connected: await database_.disconnect() +app = FastAPI(lifespan=lifespan) +metadata = sqlalchemy.MetaData() +database = databases.Database("sqlite:///test.db") +app.state.database = database + class Category(ormar.Model): ormar_config = ormar_base_config.copy(tablename="categories") diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index c2a825415..e1895377e 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -28,6 +28,7 @@ def __init__( self, metadata: Optional[sqlalchemy.MetaData] = None, database: Optional[databases.Database] = None, + engine: Optional[sqlalchemy.engine.Engine] = None, tablename: Optional[str] = None, order_by: Optional[List[str]] = None, abstract: bool = False, @@ -39,6 +40,7 @@ def __init__( self.pkname = None # type: ignore self.metadata = metadata self.database = database # type: ignore + self.engine = engine # type: ignore self.tablename = tablename # type: ignore self.orders_by = order_by or [] self.columns: List[sqlalchemy.Column] = [] @@ -60,6 +62,7 @@ def copy( self, metadata: Optional[sqlalchemy.MetaData] = None, database: Optional[databases.Database] = None, + engine: Optional[sqlalchemy.engine.Engine] = None, tablename: Optional[str] = None, order_by: Optional[List[str]] = None, abstract: Optional[bool] = None, @@ -71,6 +74,7 @@ def copy( return OrmarConfig( metadata=metadata or self.metadata, database=database or self.database, + engine=engine or self.engine, tablename=tablename, order_by=order_by, abstract=abstract or self.abstract, diff --git a/tests/lifespan.py b/tests/lifespan.py new file mode 100644 index 000000000..684f358fd --- /dev/null +++ b/tests/lifespan.py @@ -0,0 +1,33 @@ +import pytest +import sqlalchemy + +from contextlib import asynccontextmanager +from fastapi import FastAPI +from typing import AsyncIterator + + +def lifespan(config): + @asynccontextmanager + async def do_lifespan(_: FastAPI) -> AsyncIterator[None]: + if not config.database.is_connected: + await config.database.connect() + + yield + + if config.database.is_connected: + await config.database.disconnect() + + return do_lifespan + + +def init_tests(config, scope="module"): + @pytest.fixture(autouse=True, scope=scope) + def create_database(): + config.engine = sqlalchemy.create_engine(config.database.url._url) + config.metadata.create_all(config.engine) + + yield + + config.metadata.drop_all(config.engine) + + return create_database diff --git a/tests/settings.py b/tests/settings.py index be1bed2a8..b2b7c9e19 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -1,9 +1,23 @@ import os import databases +import ormar +import sqlalchemy DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///test.db") database_url = databases.DatabaseURL(DATABASE_URL) if database_url.scheme == "postgresql+aiopg": # pragma no cover DATABASE_URL = str(database_url.replace(driver=None)) print("USED DB:", DATABASE_URL) + + +def create_config(**args): + database_ = databases.Database(DATABASE_URL, **args) + metadata_ = sqlalchemy.MetaData() + engine_ = sqlalchemy.create_engine(DATABASE_URL) + + return ormar.OrmarConfig( + metadata=metadata_, + database=database_, + engine=engine_, + ) diff --git a/tests/test_deferred/test_forward_cross_refs.py b/tests/test_deferred/test_forward_cross_refs.py index 3e1aa747f..56af4d776 100644 --- a/tests/test_deferred/test_forward_cross_refs.py +++ b/tests/test_deferred/test_forward_cross_refs.py @@ -1,25 +1,17 @@ # type: ignore from typing import ForwardRef, List, Optional -import databases import ormar import pytest -import sqlalchemy as sa -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sa.MetaData() -db = databases.Database(DATABASE_URL) -engine = create_engine(DATABASE_URL) -TeacherRef = ForwardRef("Teacher") +base_ormar_config = create_config() -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, -) +TeacherRef = ForwardRef("Teacher") class Student(ormar.Model): @@ -76,17 +68,13 @@ class City(ormar.Model): Country.update_forward_refs() -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_double_relations(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): t1 = await Teacher.objects.create(name="Mr. Jones") t2 = await Teacher.objects.create(name="Ms. Smith") t3 = await Teacher.objects.create(name="Mr. Quibble") @@ -143,8 +131,8 @@ async def test_double_relations(): @pytest.mark.asyncio async def test_auto_through_model(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): england = await Country(name="England").save() france = await Country(name="France").save() london = await City(name="London", country=england).save() diff --git a/tests/test_deferred/test_forward_refs.py b/tests/test_deferred/test_forward_refs.py index 0d2d31981..7842d37af 100644 --- a/tests/test_deferred/test_forward_refs.py +++ b/tests/test_deferred/test_forward_refs.py @@ -1,28 +1,24 @@ # type: ignore from typing import ForwardRef, List, Optional -import databases import ormar import pytest import pytest_asyncio import sqlalchemy as sa from ormar.exceptions import ModelError -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests + + +base_ormar_config = create_config() -metadata = sa.MetaData() -db = databases.Database(DATABASE_URL) -engine = create_engine(DATABASE_URL) PersonRef = ForwardRef("Person") class Person(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -37,10 +33,7 @@ class Person(ormar.Model): class Child(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -54,17 +47,11 @@ class Child(ormar.Model): class ChildFriend(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() class Game(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -73,17 +60,13 @@ class Game(ormar.Model): Child.update_forward_refs() -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(scope="function") async def cleanup(): yield - async with db: + async with base_ormar_config.database: await ChildFriend.objects.delete(each=True) await Child.objects.delete(each=True) await Game.objects.delete(each=True) @@ -95,10 +78,7 @@ async def test_not_updated_model_raises_errors(): Person2Ref = ForwardRef("Person2") class Person2(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -119,16 +99,10 @@ async def test_not_updated_model_m2m_raises_errors(): Person3Ref = ForwardRef("Person3") class PersonFriend(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() class Person3(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -151,19 +125,13 @@ async def test_not_updated_model_m2m_through_raises_errors(): PersonPetRef = ForwardRef("PersonPet") class Pet(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Person4(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -172,10 +140,7 @@ class Person4(ormar.Model): ) class PersonPet(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() with pytest.raises(ModelError): await Person4.objects.create(name="Test") @@ -205,8 +170,8 @@ def test_proper_field_init(): @pytest.mark.asyncio async def test_self_relation(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): sam = await Person.objects.create(name="Sam") joe = await Person(name="Joe", supervisor=sam).save() assert joe.supervisor.name == "Sam" @@ -223,8 +188,8 @@ async def test_self_relation(): @pytest.mark.asyncio async def test_other_forwardref_relation(cleanup): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): checkers = await Game.objects.create(name="checkers") uno = await Game(name="Uno").save() @@ -250,8 +215,8 @@ async def test_other_forwardref_relation(cleanup): @pytest.mark.asyncio async def test_m2m_self_forwardref_relation(cleanup): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): checkers = await Game.objects.create(name="Checkers") uno = await Game(name="Uno").save() jenga = await Game(name="Jenga").save() diff --git a/tests/test_deferred/test_more_same_table_joins.py b/tests/test_deferred/test_more_same_table_joins.py index 38c73bd38..5cebb79d6 100644 --- a/tests/test_deferred/test_more_same_table_joins.py +++ b/tests/test_deferred/test_more_same_table_joins.py @@ -1,44 +1,31 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config(force_rollback=True) class Department(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="departments", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="departments") id: int = ormar.Integer(primary_key=True, autoincrement=False) name: str = ormar.String(max_length=100) class SchoolClass(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="schoolclasses", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="schoolclasses") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -46,11 +33,7 @@ class Category(ormar.Model): class Student(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="students", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="students") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -59,11 +42,7 @@ class Student(ormar.Model): class Teacher(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="teachers", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="teachers") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -71,13 +50,7 @@ class Teacher(ormar.Model): category: Optional[Category] = ormar.ForeignKey(Category, nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) async def create_data(): @@ -95,7 +68,7 @@ async def create_data(): @pytest.mark.asyncio async def test_model_multiple_instances_of_same_table_in_schema(): - async with database: + async with base_ormar_config.database: await create_data() classes = await SchoolClass.objects.select_related( ["teachers__category__department", "students__category__department"] @@ -109,7 +82,7 @@ async def test_model_multiple_instances_of_same_table_in_schema(): @pytest.mark.asyncio async def test_load_all_multiple_instances_of_same_table_in_schema(): - async with database: + async with base_ormar_config.database: await create_data() math_class = await SchoolClass.objects.get(name="Math") assert math_class.name == "Math" @@ -123,7 +96,7 @@ async def test_load_all_multiple_instances_of_same_table_in_schema(): @pytest.mark.asyncio async def test_filter_groups_with_instances_of_same_table_in_schema(): - async with database: + async with base_ormar_config.database: await create_data() math_class = ( await SchoolClass.objects.select_related( diff --git a/tests/test_deferred/test_same_table_joins.py b/tests/test_deferred/test_same_table_joins.py index 17667db9c..548fded6b 100644 --- a/tests/test_deferred/test_same_table_joins.py +++ b/tests/test_deferred/test_same_table_joins.py @@ -1,33 +1,24 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Department(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="departments", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="departments") id: int = ormar.Integer(primary_key=True, autoincrement=False) name: str = ormar.String(max_length=100) class SchoolClass(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="schoolclasses", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="schoolclasses") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -35,22 +26,14 @@ class SchoolClass(ormar.Model): class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Student(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="students", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="students") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -59,11 +42,7 @@ class Student(ormar.Model): class Teacher(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="teachers", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="teachers") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -71,13 +50,7 @@ class Teacher(ormar.Model): category: Optional[Category] = ormar.ForeignKey(Category, nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) async def create_data(): @@ -95,8 +68,8 @@ async def create_data(): @pytest.mark.asyncio async def test_model_multiple_instances_of_same_table_in_schema(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await create_data() classes = await SchoolClass.objects.select_related( ["teachers__category", "students__schoolclass"] @@ -123,8 +96,8 @@ async def test_model_multiple_instances_of_same_table_in_schema(): @pytest.mark.asyncio async def test_right_tables_join(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await create_data() classes = await SchoolClass.objects.select_related( ["teachers__category", "students"] @@ -138,8 +111,8 @@ async def test_right_tables_join(): @pytest.mark.asyncio async def test_multiple_reverse_related_objects(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await create_data() classes = await SchoolClass.objects.select_related( ["teachers__category", "students__category"] diff --git a/tests/test_encryption/test_encrypted_columns.py b/tests/test_encryption/test_encrypted_columns.py index 65f341ec9..589886fd8 100644 --- a/tests/test_encryption/test_encrypted_columns.py +++ b/tests/test_encryption/test_encrypted_columns.py @@ -6,24 +6,16 @@ import uuid from typing import Any -import databases import ormar import pytest -import sqlalchemy from ormar import ModelDefinitionError, NoMatch from ormar.fields.sqlalchemy_encrypted import EncryptedString -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() default_fernet = dict( encrypt_secret="asd123", encrypt_backend=ormar.EncryptBackends.FERNET ) @@ -108,13 +100,7 @@ class Report(ormar.Model): filters = ormar.ManyToMany(Filter) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_error_on_encrypted_pk(): @@ -178,7 +164,7 @@ def test_db_structure(): @pytest.mark.asyncio async def test_save_and_retrieve(): - async with database: + async with base_ormar_config.database: test_uuid = uuid.uuid4() await Author( name="Test", @@ -222,7 +208,7 @@ async def test_save_and_retrieve(): @pytest.mark.asyncio async def test_fernet_filters_nomatch(): - async with database: + async with base_ormar_config.database: await Filter(name="test1").save() await Filter(name="test1").save() @@ -237,7 +223,7 @@ async def test_fernet_filters_nomatch(): @pytest.mark.asyncio async def test_hash_filters_works(): - async with database: + async with base_ormar_config.database: await Hash(name="test1").save() await Hash(name="test2").save() @@ -254,7 +240,7 @@ async def test_hash_filters_works(): @pytest.mark.asyncio async def test_related_model_fields_properly_decrypted(): - async with database: + async with base_ormar_config.database: hash1 = await Hash(name="test1").save() report = await Report.objects.create(name="Report1") await report.filters.create(name="test1", hash=hash1) diff --git a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py index 2cc5a076c..a70c74c58 100644 --- a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py +++ b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py @@ -7,16 +7,10 @@ import pytest import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - - -base_ormar_config = orm.OrmarConfig( - database=database, - metadata=metadata, -) +base_ormar_config = create_config() class ChagenlogRelease(orm.Model): @@ -304,18 +298,12 @@ class Webhook(orm.Model): error: str = orm.Text(default="") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_very_complex_relation_map(): - async with database: + async with base_ormar_config.database: tags = [ {"id": 18, "name": "name-18", "ref": "ref-18"}, {"id": 17, "name": "name-17", "ref": "ref-17"}, diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index 4a5eb0108..060b531c5 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -1,20 +1,13 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Role(ormar.Model): @@ -58,6 +51,9 @@ class Item(ormar.Model): created_by: Optional[User] = ormar.ForeignKey(User) +create_test_database = init_tests(base_ormar_config) + + @pytest.fixture(autouse=True, scope="module") def sample_data(): role = Role(name="User", id=1) diff --git a/tests/test_exclude_include_dict/test_excludable_items.py b/tests/test_exclude_include_dict/test_excludable_items.py index c93f6a691..e1fa142ff 100644 --- a/tests/test_exclude_include_dict/test_excludable_items.py +++ b/tests/test_exclude_include_dict/test_excludable_items.py @@ -1,20 +1,12 @@ from typing import List, Optional -import databases import ormar -import sqlalchemy from ormar.models.excludable import ExcludableItems -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class NickNames(ormar.Model): @@ -58,6 +50,9 @@ class Car(ormar.Model): aircon_type: str = ormar.String(max_length=20, nullable=True) +create_test_database = init_tests(base_ormar_config) + + def compare_results(excludable): car_excludable = excludable.get(Car) assert car_excludable.exclude == {"year", "gearbox_type", "gears", "aircon_type"} diff --git a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py index 00bfe8ed8..50120301e 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py @@ -13,26 +13,12 @@ from ormar import post_save from pydantic import ConfigDict, computed_field -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) -app.state.database = database - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) # note that you can set orm_mode here @@ -60,11 +46,7 @@ def gen_pass(): class RandomModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="random_users", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="random_users") id: int = ormar.Integer(primary_key=True) password: str = ormar.String(max_length=255, default=gen_pass) @@ -80,11 +62,7 @@ def full_name(self) -> str: class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users") id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255) @@ -95,11 +73,7 @@ class User(ormar.Model): class User2(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users2", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users2") id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255, nullable=False) @@ -110,12 +84,7 @@ class User2(ormar.Model): timestamp: datetime.datetime = pydantic.Field(default=datetime.datetime.now) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @app.post("/users/", response_model=User, response_model_exclude={"password"}) diff --git a/tests/test_exclude_include_dict/test_excluding_fields_with_default.py b/tests/test_exclude_include_dict/test_excluding_fields_with_default.py index b754672a9..23c5f87be 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_with_default.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_with_default.py @@ -1,15 +1,14 @@ import random from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() def get_position() -> int: @@ -17,11 +16,7 @@ def get_position() -> int: class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -29,11 +24,7 @@ class Album(ormar.Model): class Track(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tracks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tracks") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -42,19 +33,13 @@ class Track(ormar.Model): play_count: int = ormar.Integer(nullable=True, default=0) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_excluding_field_with_default(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): album = await Album.objects.create(name="Miami") await Track.objects.create(title="Vice City", album=album, play_count=10) await Track.objects.create(title="Beach Sand", album=album, play_count=20) diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index 3d13942b5..d3f3aa845 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -1,23 +1,18 @@ from typing import Optional -import databases import ormar import pydantic import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Company(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="companies", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False) @@ -25,11 +20,7 @@ class Company(ormar.Model): class Car(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="cars", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="cars") id: int = ormar.Integer(primary_key=True) manufacturer: Optional[Company] = ormar.ForeignKey(Company) @@ -40,19 +31,13 @@ class Car(ormar.Model): aircon_type: str = ormar.String(max_length=20, nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_selecting_subset(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): toyota = await Company.objects.create(name="Toyota", founded=1937) await Car.objects.create( manufacturer=toyota, @@ -184,8 +169,8 @@ async def test_selecting_subset(): @pytest.mark.asyncio async def test_excluding_nested_lists_in_dump(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): toyota = await Company.objects.create(name="Toyota", founded=1937) car1 = await Car.objects.create( manufacturer=toyota, diff --git a/tests/test_exclude_include_dict/test_pydantic_dict_params.py b/tests/test_exclude_include_dict/test_pydantic_dict_params.py index a58bdc635..a16d97e3a 100644 --- a/tests/test_exclude_include_dict/test_pydantic_dict_params.py +++ b/tests/test_exclude_include_dict/test_pydantic_dict_params.py @@ -1,22 +1,17 @@ from typing import List -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) + +base_ormar_config = create_config() class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="Test", nullable=True) @@ -24,11 +19,7 @@ class Category(ormar.Model): class Item(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="items", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="items") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -36,17 +27,12 @@ class Item(ormar.Model): categories: List[Category] = ormar.ManyToMany(Category) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_exclude_default(): - async with database: + async with base_ormar_config.database: category = Category() assert category.model_dump() == { "id": None, @@ -70,7 +56,7 @@ async def test_exclude_default(): @pytest.mark.asyncio async def test_exclude_none(): - async with database: + async with base_ormar_config.database: category = Category(id=2, name=None) assert category.model_dump() == { "id": 2, @@ -105,7 +91,7 @@ async def test_exclude_none(): @pytest.mark.asyncio async def test_exclude_unset(): - async with database: + async with base_ormar_config.database: category = Category(id=3, name="Test 2") assert category.model_dump() == { "id": 3, diff --git a/tests/test_fastapi/test_binary_fields.py b/tests/test_fastapi/test_binary_fields.py index cd387f2a2..3142cbd62 100644 --- a/tests/test_fastapi/test_binary_fields.py +++ b/tests/test_fastapi/test_binary_fields.py @@ -1,35 +1,21 @@ import base64 import uuid -from contextlib import asynccontextmanager from enum import Enum -from typing import AsyncIterator, List +from typing import List -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import lifespan, init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() headers = {"content-type": "application/json"} - - -@asynccontextmanager -async def lifespan(app: FastAPI) -> AsyncIterator[None]: - if not database.is_connected: - await database.connect() - yield - if database.is_connected: - await database.disconnect() - - -app = FastAPI(lifespan=lifespan) +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) blob3 = b"\xc3\x83\x28" @@ -38,12 +24,6 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]: blob6 = b"\xff" -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) - - class BinaryEnum(Enum): blob3 = blob3 blob4 = blob4 @@ -59,6 +39,9 @@ class BinaryThing(ormar.Model): bt: str = ormar.LargeBinary(represent_as_base64_str=True, max_length=100) +create_test_database = init_tests(base_ormar_config) + + @app.get("/things", response_model=List[BinaryThing]) async def read_things(): return await BinaryThing.objects.order_by("name").all() @@ -70,14 +53,6 @@ async def create_things(thing: BinaryThing): return thing -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) - - @pytest.mark.asyncio async def test_read_main(): client = AsyncClient(app=app, base_url="http://testserver") diff --git a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py index c7f285fa5..943653f77 100644 --- a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py +++ b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py @@ -1,24 +1,18 @@ from typing import Optional from uuid import UUID, uuid4 -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -app = FastAPI() -DATABASE_URL = "sqlite:///db.sqlite" -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() +from tests.settings import create_config +from tests.lifespan import lifespan, init_tests -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class CA(ormar.Model): @@ -44,6 +38,9 @@ class CB2(ormar.Model): ca2: Optional[CA] = ormar.ForeignKey(CA, nullable=True) +create_test_database = init_tests(base_ormar_config) + + @app.get("/ca", response_model=CA) async def get_ca(): # pragma: no cover return None diff --git a/tests/test_fastapi/test_enum_schema.py b/tests/test_fastapi/test_enum_schema.py index fa1ac6b5b..a6431128c 100644 --- a/tests/test_fastapi/test_enum_schema.py +++ b/tests/test_fastapi/test_enum_schema.py @@ -1,13 +1,12 @@ from enum import Enum -import databases import ormar -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class MyEnum(Enum): @@ -16,16 +15,15 @@ class MyEnum(Enum): class EnumExample(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="enum_example", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="enum_example") id: int = ormar.Integer(primary_key=True) size: MyEnum = ormar.Enum(enum_class=MyEnum, default=MyEnum.SMALL) +create_test_database = init_tests(base_ormar_config) + + def test_proper_schema(): schema = EnumExample.model_json_schema() assert {"MyEnum": {"title": "MyEnum", "enum": [1, 2], "type": "integer"}} == schema[ diff --git a/tests/test_fastapi/test_excludes_with_get_pydantic.py b/tests/test_fastapi/test_excludes_with_get_pydantic.py index 0db526ced..a06a6e365 100644 --- a/tests/test_fastapi/test_excludes_with_get_pydantic.py +++ b/tests/test_fastapi/test_excludes_with_get_pydantic.py @@ -1,41 +1,45 @@ +import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient +from typing import ForwardRef, Optional + +from tests.settings import create_config +from tests.lifespan import lifespan, init_tests + + +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) + + +class SelfRef(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="self_refs") + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100, default="selfref") + parent = ormar.ForeignKey(ForwardRef("SelfRef"), related_name="children") + + +SelfRef.update_forward_refs() -from tests.settings import DATABASE_URL -from tests.test_inheritance_and_pydantic_generation.test_geting_pydantic_models import ( - Category, - SelfRef, - database, - metadata, -) -app = FastAPI() -app.state.database = database +class Category(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="categories") + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() +class Item(ormar.Model): + ormar_config = base_ormar_config.copy() -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100, default="test") + category: Optional[Category] = ormar.ForeignKey(Category, nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) async def create_category(category: Category): diff --git a/tests/test_fastapi/test_excluding_fields.py b/tests/test_fastapi/test_excluding_fields.py index 6a11e7b53..6c33a1711 100644 --- a/tests/test_fastapi/test_excluding_fields.py +++ b/tests/test_fastapi/test_excluding_fields.py @@ -1,64 +1,35 @@ from typing import List -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) -app.state.database = database - - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="items", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="items") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) categories: List[Category] = ormar.ManyToMany(Category) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) + @app.post("/items/", response_model=Item) diff --git a/tests/test_fastapi/test_extra_ignore_parameter.py b/tests/test_fastapi/test_extra_ignore_parameter.py index 1d1447a99..71b1219db 100644 --- a/tests/test_fastapi/test_extra_ignore_parameter.py +++ b/tests/test_fastapi/test_extra_ignore_parameter.py @@ -1,51 +1,26 @@ -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient from ormar import Extra -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) -app.state.database = database - - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class Item(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - extra=Extra.ignore, - ) + ormar_config = base_ormar_config.copy(extra=Extra.ignore) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) + @app.post("/item/", response_model=Item) diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index a3735c967..698a4ae35 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -1,42 +1,20 @@ import datetime from typing import List, Optional, Union -import databases import ormar import pydantic import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient from pydantic import Field -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) -app.state.database = database - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() - - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class PTestA(pydantic.BaseModel): @@ -68,12 +46,8 @@ class Item(ormar.Model): categories = ormar.ManyToMany(Category) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) + @app.get("/items/", response_model=List[Item]) diff --git a/tests/test_fastapi/test_fastapi_usage.py b/tests/test_fastapi/test_fastapi_usage.py index d276d4c36..ed2f9046e 100644 --- a/tests/test_fastapi/test_fastapi_usage.py +++ b/tests/test_fastapi/test_fastapi_usage.py @@ -1,44 +1,38 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import lifespan, init_tests -app = FastAPI() -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="items", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="items") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) category: Optional[Category] = ormar.ForeignKey(Category, nullable=True) +create_test_database = init_tests(base_ormar_config) + + + @app.post("/items/", response_model=Item) async def create_item(item: Item): return item diff --git a/tests/test_fastapi/test_inheritance_concrete_fastapi.py b/tests/test_fastapi/test_inheritance_concrete_fastapi.py index c8f4251f0..3504a4989 100644 --- a/tests/test_fastapi/test_inheritance_concrete_fastapi.py +++ b/tests/test_fastapi/test_inheritance_concrete_fastapi.py @@ -1,43 +1,141 @@ import datetime -from typing import List +from typing import List, Optional import pytest -import sqlalchemy +import ormar from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient +from ormar.relations.relation_proxy import RelationProxy +from pydantic import computed_field -from tests.settings import DATABASE_URL -from tests.test_inheritance_and_pydantic_generation.test_inheritance_concrete import ( # noqa: E501 - Bus, - Bus2, - Category, - Person, - Subject, - Truck, - Truck2, - metadata, -) -from tests.test_inheritance_and_pydantic_generation.test_inheritance_concrete import ( - db as database, -) +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -app.state.database = database +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() +class AuditModel(ormar.Model): + ormar_config = base_ormar_config.copy(abstract=True) + + created_by: str = ormar.String(max_length=100) + updated_by: str = ormar.String(max_length=100, default="Sam") + + @computed_field + def audit(self) -> str: # pragma: no cover + return f"{self.created_by} {self.updated_by}" + + +class DateFieldsModelNoSubclass(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="test_date_models") + + date_id: int = ormar.Integer(primary_key=True) + created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) + updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) + + +class DateFieldsModel(ormar.Model): + ormar_config = base_ormar_config.copy( + abstract=True, + constraints=[ + ormar.fields.constraints.UniqueColumns( + "creation_date", + "modification_date", + ), + ormar.fields.constraints.CheckColumns( + "creation_date <= modification_date", + ), + ], + ) + + created_date: datetime.datetime = ormar.DateTime( + default=datetime.datetime.now, name="creation_date" + ) + updated_date: datetime.datetime = ormar.DateTime( + default=datetime.datetime.now, name="modification_date" + ) + + +class Person(ormar.Model): + ormar_config = base_ormar_config.copy() + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + + +class Car(ormar.Model): + ormar_config = base_ormar_config.copy(abstract=True) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=50) + owner: Person = ormar.ForeignKey(Person) + co_owner: Person = ormar.ForeignKey(Person, related_name="coowned") + created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) + + +class Car2(ormar.Model): + ormar_config = base_ormar_config.copy(abstract=True) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=50) + owner: Person = ormar.ForeignKey(Person, related_name="owned") + co_owners: RelationProxy[Person] = ormar.ManyToMany(Person, related_name="coowned") + created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) + + +class Bus(Car): + ormar_config = base_ormar_config.copy(tablename="buses") + + owner: Person = ormar.ForeignKey(Person, related_name="buses") + max_persons: int = ormar.Integer() + + +class Bus2(Car2): + ormar_config = base_ormar_config.copy(tablename="buses2") + + max_persons: int = ormar.Integer() + + +class Category(DateFieldsModel, AuditModel): + ormar_config = base_ormar_config.copy(tablename="categories") + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=50, unique=True, index=True) + code: int = ormar.Integer() + + @computed_field + def code_name(self) -> str: + return f"{self.code}:{self.name}" + + @computed_field + def audit(self) -> str: + return f"{self.created_by} {self.updated_by}" + + +class Subject(DateFieldsModel): + ormar_config = base_ormar_config.copy() + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=50, unique=True, index=True) + category: Optional[Category] = ormar.ForeignKey(Category) + + +class Truck(Car): + ormar_config = base_ormar_config.copy() + + max_capacity: int = ormar.Integer() + + +class Truck2(Car2): + ormar_config = base_ormar_config.copy(tablename="trucks2") + + max_capacity: int = ormar.Integer() + + +create_test_database = init_tests(base_ormar_config) -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() @app.post("/subjects/", response_model=Subject) @@ -113,14 +211,6 @@ async def add_truck_coowner(item_id: int, person: Person): return truck -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) - - @pytest.mark.asyncio async def test_read_main(): client = AsyncClient(app=app, base_url="http://testserver") diff --git a/tests/test_fastapi/test_inheritance_mixins_fastapi.py b/tests/test_fastapi/test_inheritance_mixins_fastapi.py index 20223c038..fa7289079 100644 --- a/tests/test_fastapi/test_inheritance_mixins_fastapi.py +++ b/tests/test_fastapi/test_inheritance_mixins_fastapi.py @@ -1,37 +1,48 @@ import datetime import pytest -import sqlalchemy +import ormar from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient +from typing import Optional -from tests.settings import DATABASE_URL -from tests.test_inheritance_and_pydantic_generation.test_inheritance_mixins import ( # noqa: E501 - Category, - Subject, - metadata, -) -from tests.test_inheritance_and_pydantic_generation.test_inheritance_mixins import ( - db as database, -) +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -app.state.database = database +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() +class AuditMixin: + created_by: str = ormar.String(max_length=100) + updated_by: str = ormar.String(max_length=100, default="Sam") + + +class DateFieldsMixins: + created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) + updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) + + +class Category(ormar.Model, DateFieldsMixins, AuditMixin): + ormar_config = base_ormar_config.copy(tablename="categories") + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=50, unique=True, index=True) + code: int = ormar.Integer() + + +class Subject(ormar.Model, DateFieldsMixins): + ormar_config = base_ormar_config.copy(tablename="subjects") + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=50, unique=True, index=True) + category: Optional[Category] = ormar.ForeignKey(Category) + + +create_test_database = init_tests(base_ormar_config) -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() @app.post("/subjects/", response_model=Subject) @@ -45,14 +56,6 @@ async def create_category(category: Category): return category -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) - - @pytest.mark.asyncio async def test_read_main(): client = AsyncClient(app=app, base_url="http://testserver") diff --git a/tests/test_fastapi/test_json_field_fastapi.py b/tests/test_fastapi/test_json_field_fastapi.py index ff11f458c..394e23e38 100644 --- a/tests/test_fastapi/test_json_field_fastapi.py +++ b/tests/test_fastapi/test_json_field_fastapi.py @@ -2,42 +2,19 @@ import uuid from typing import List -import databases import ormar import pydantic import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() -app.state.database = database - - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() - - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class Thing(ormar.Model): @@ -48,6 +25,9 @@ class Thing(ormar.Model): js: pydantic.Json = ormar.JSON() +create_test_database = init_tests(base_ormar_config) + + @app.get("/things", response_model=List[Thing]) async def read_things(): return await Thing.objects.order_by("name").all() @@ -87,14 +67,6 @@ async def read_things_untyped(): return await Thing.objects.order_by("name").all() -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) - - @pytest.mark.asyncio async def test_json_is_required_if_not_nullable(): with pytest.raises(pydantic.ValidationError): @@ -115,7 +87,7 @@ class Thing2(ormar.Model): @pytest.mark.asyncio async def test_setting_values_after_init(): - async with database: + async with base_ormar_config.database: t1 = Thing(id="67a82813-d90c-45ff-b546-b4e38d7030d7", name="t1", js=["thing1"]) assert '["thing1"]' in t1.model_dump_json() await t1.save() diff --git a/tests/test_fastapi/test_m2m_forwardref.py b/tests/test_fastapi/test_m2m_forwardref.py index 9950890a2..4d5e5f1f7 100644 --- a/tests/test_fastapi/test_m2m_forwardref.py +++ b/tests/test_fastapi/test_m2m_forwardref.py @@ -1,41 +1,18 @@ from typing import ForwardRef, List, Optional -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient from starlette import status -app = FastAPI() -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() -app.state.database = database - - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() - - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) CityRef = ForwardRef("City") @@ -74,12 +51,8 @@ class City(ormar.Model): Country.update_forward_refs() -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) + @app.post("/", response_model=Country, status_code=status.HTTP_201_CREATED) diff --git a/tests/test_fastapi/test_more_reallife_fastapi.py b/tests/test_fastapi/test_more_reallife_fastapi.py index 0fcd01501..3540ad31c 100644 --- a/tests/test_fastapi/test_more_reallife_fastapi.py +++ b/tests/test_fastapi/test_more_reallife_fastapi.py @@ -1,64 +1,36 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) -app.state.database = database - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="items", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="items") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) category: Optional[Category] = ormar.ForeignKey(Category, nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) + @app.get("/items", response_model=List[Item]) diff --git a/tests/test_fastapi/test_nested_saving.py b/tests/test_fastapi/test_nested_saving.py index 48d9144a8..e5827ca66 100644 --- a/tests/test_fastapi/test_nested_saving.py +++ b/tests/test_fastapi/test_nested_saving.py @@ -1,53 +1,30 @@ from typing import Any, Dict, Optional, Set, Type, Union, cast -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient from ormar.queryset.utils import translate_list_to_dict -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) -app.state.database = database +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) headers = {"content-type": "application/json"} -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() - - class Department(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) department_name: str = ormar.String(max_length=100) class Course(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) course_name: str = ormar.String(max_length=100) @@ -56,25 +33,13 @@ class Course(ormar.Model): class Student(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) courses = ormar.ManyToMany(Course) -# create db and tables -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) - - to_exclude = { "id": ..., "courses": { @@ -90,6 +55,9 @@ def create_test_database(): } +create_test_database = init_tests(base_ormar_config) + + def auto_exclude_id_field(to_exclude: Any) -> Union[Dict, Set]: if isinstance(to_exclude, dict): for key in to_exclude.keys(): diff --git a/tests/test_fastapi/test_recursion_error.py b/tests/test_fastapi/test_recursion_error.py index 9eb34b07a..962d0a21e 100644 --- a/tests/test_fastapi/test_recursion_error.py +++ b/tests/test_fastapi/test_recursion_error.py @@ -2,39 +2,21 @@ from datetime import datetime from typing import List -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import Depends, FastAPI from httpx import AsyncClient from pydantic import BaseModel, Json -from tests.settings import DATABASE_URL - -router = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) -router.state.database = database +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config +base_ormar_config = create_config() +router = FastAPI(lifespan=lifespan(base_ormar_config)) headers = {"content-type": "application/json"} -@router.on_event("startup") -async def startup() -> None: - database_ = router.state.database - if not database_.is_connected: - await database_.connect() - - -@router.on_event("shutdown") -async def shutdown() -> None: - database_ = router.state.database - if database_.is_connected: - await database_.disconnect() - - class User(ormar.Model): """ The user model @@ -48,11 +30,7 @@ class User(ormar.Model): verify_key: str = ormar.String(unique=True, max_length=100, nullable=True) created_at: datetime = ormar.DateTime(default=datetime.now()) - ormar_config = ormar.OrmarConfig( - tablename="users", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users") class UserSession(ormar.Model): @@ -65,11 +43,7 @@ class UserSession(ormar.Model): session_key: str = ormar.String(unique=True, max_length=64) created_at: datetime = ormar.DateTime(default=datetime.now()) - ormar_config = ormar.OrmarConfig( - tablename="user_sessions", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="user_sessions") class QuizAnswer(BaseModel): @@ -97,19 +71,11 @@ class Quiz(ormar.Model): user_id: uuid.UUID = ormar.UUID(foreign_key=User.id) questions: Json = ormar.JSON(nullable=False) - ormar_config = ormar.OrmarConfig( - tablename="quiz", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="quiz") + +create_test_database = init_tests(base_ormar_config) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) async def get_current_user(): diff --git a/tests/test_fastapi/test_relations_with_nested_defaults.py b/tests/test_fastapi/test_relations_with_nested_defaults.py index 139eb1958..6a7a4a8bd 100644 --- a/tests/test_fastapi/test_relations_with_nested_defaults.py +++ b/tests/test_fastapi/test_relations_with_nested_defaults.py @@ -1,41 +1,18 @@ from typing import Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() -app = FastAPI() -app.state.database = database - - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() - - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class Country(ormar.Model): @@ -63,17 +40,12 @@ class Book(ormar.Model): year: int = ormar.Integer(nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture async def sample_data(): - async with database: + async with base_ormar_config.database: country = await Country(id=1, name="USA").save() author = await Author(id=1, name="bug", rating=5, country=country).save() await Book( diff --git a/tests/test_fastapi/test_schema_not_allowed_params.py b/tests/test_fastapi/test_schema_not_allowed_params.py index 7384f5825..c5555802c 100644 --- a/tests/test_fastapi/test_schema_not_allowed_params.py +++ b/tests/test_fastapi/test_schema_not_allowed_params.py @@ -2,15 +2,11 @@ import ormar import sqlalchemy -DATABASE_URL = "sqlite:///db.sqlite" -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() +from tests.lifespan import init_tests +from tests.settings import create_config -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -21,6 +17,9 @@ class Author(ormar.Model): contents: str = ormar.Text() +create_test_database = init_tests(base_ormar_config) + + def test_schema_not_allowed(): schema = Author.model_json_schema() for field_schema in schema.get("properties").values(): diff --git a/tests/test_fastapi/test_skip_reverse_models.py b/tests/test_fastapi/test_skip_reverse_models.py index 4e879e2ff..5eef08573 100644 --- a/tests/test_fastapi/test_skip_reverse_models.py +++ b/tests/test_fastapi/test_skip_reverse_models.py @@ -1,43 +1,20 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) -app.state.database = database +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) headers = {"content-type": "application/json"} -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() - - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) - - class Author(ormar.Model): ormar_config = base_ormar_config.copy() @@ -66,12 +43,8 @@ class Post(ormar.Model): author: Optional[Author] = ormar.ForeignKey(Author, skip_reverse=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) + @app.post("/categories/forbid/", response_model=Category2) diff --git a/tests/test_fastapi/test_wekref_exclusion.py b/tests/test_fastapi/test_wekref_exclusion.py index 83149e0cd..6002dc484 100644 --- a/tests/test_fastapi/test_wekref_exclusion.py +++ b/tests/test_fastapi/test_wekref_exclusion.py @@ -1,51 +1,19 @@ from typing import List, Optional from uuid import UUID, uuid4 -import databases import ormar import pydantic import pytest -import sqlalchemy from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from tests.settings import DATABASE_URL +from tests.lifespan import lifespan, init_tests +from tests.settings import create_config -app = FastAPI() -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -app.state.database = database - - -@app.on_event("startup") -async def startup() -> None: - database_ = app.state.database - if not database_.is_connected: - await database_.connect() - - -@app.on_event("shutdown") -async def shutdown() -> None: - database_ = app.state.database - if database_.is_connected: - await database_.disconnect() - - -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) - - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() +app = FastAPI(lifespan=lifespan(base_ormar_config)) class OtherThing(ormar.Model): @@ -65,6 +33,10 @@ class Thing(ormar.Model): other_thing: Optional[OtherThing] = ormar.ForeignKey(OtherThing, nullable=True) +create_test_database = init_tests(base_ormar_config) + + + @app.post("/test/1") async def post_test_1(): # don't split initialization and attribute assignment diff --git a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py index e7ac3c29e..a50cd0977 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py +++ b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py @@ -1,49 +1,38 @@ import datetime -import databases import ormar import pytest -import sqlalchemy as sa -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sa.MetaData() -db = databases.Database(DATABASE_URL) -engine = create_engine(DATABASE_URL) + +base_ormar_config = create_config() class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="users") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) class RelationalAuditModel(ormar.Model): - ormar_config = ormar.OrmarConfig(abstract=True) + ormar_config = base_ormar_config.copy(abstract=True) created_by: User = ormar.ForeignKey(User, nullable=False) updated_by: User = ormar.ForeignKey(User, nullable=False) class AuditModel(ormar.Model): - ormar_config = ormar.OrmarConfig(abstract=True) + ormar_config = base_ormar_config.copy(abstract=True) created_by: str = ormar.String(max_length=100) updated_by: str = ormar.String(max_length=100, default="Sam") class DateFieldsModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract=True, - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(abstract=True) created_date: datetime.datetime = ormar.DateTime( default=datetime.datetime.now, name="creation_date" @@ -54,7 +43,7 @@ class DateFieldsModel(ormar.Model): class Category(DateFieldsModel, AuditModel): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( tablename="categories", exclude_parent_fields=["updated_by", "updated_date"], ) @@ -65,7 +54,7 @@ class Category(DateFieldsModel, AuditModel): class Item(DateFieldsModel, AuditModel): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( tablename="items", exclude_parent_fields=["updated_by", "updated_date"], ) @@ -77,7 +66,7 @@ class Item(DateFieldsModel, AuditModel): class Gun(RelationalAuditModel, DateFieldsModel): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( tablename="guns", exclude_parent_fields=["updated_by"], ) @@ -86,11 +75,7 @@ class Gun(RelationalAuditModel, DateFieldsModel): name: str = ormar.String(max_length=50) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_model_definition(): @@ -111,8 +96,8 @@ def test_model_definition(): @pytest.mark.asyncio async def test_model_works_as_expected(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): test = await Category(name="Cat", code=2, created_by="Joe").save() assert test.created_date is not None @@ -123,8 +108,8 @@ async def test_model_works_as_expected(): @pytest.mark.asyncio async def test_exclude_with_redefinition(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): test = await Item(name="Item", code=3, created_by="Anna").save() assert test.created_date is not None assert test.updated_by == "Bob" @@ -136,8 +121,8 @@ async def test_exclude_with_redefinition(): @pytest.mark.asyncio async def test_exclude_with_relation(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): user = await User(name="Michail Kalasznikow").save() test = await Gun(name="AK47", created_by=user).save() assert test.created_date is not None diff --git a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py index fcf6c61bb..b9f1e525c 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py +++ b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py @@ -6,16 +6,11 @@ import sqlalchemy from pydantic_core import PydanticUndefined -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class SelfRef(ormar.Model): @@ -62,6 +57,9 @@ class MutualB(ormar.Model): MutualA.update_forward_refs() +create_test_database = init_tests(base_ormar_config) + + def test_getting_pydantic_model(): PydanticCategory = Category.get_pydantic() assert issubclass(PydanticCategory, pydantic.BaseModel) diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index 4446d3451..6046e0e31 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -2,7 +2,6 @@ from collections import Counter from typing import Optional -import databases import ormar import ormar.fields.constraints import pydantic @@ -13,19 +12,15 @@ from ormar.models.metaclass import get_constraint_copy from ormar.relations.relation_proxy import RelationProxy from pydantic import computed_field -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sa.MetaData() -db = databases.Database(DATABASE_URL) -engine = create_engine(DATABASE_URL) +base_ormar_config = create_config() class AuditModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract=True, - ) + ormar_config = base_ormar_config.copy(abstract=True) created_by: str = ormar.String(max_length=100) updated_by: str = ormar.String(max_length=100, default="Sam") @@ -36,11 +31,7 @@ def audit(self) -> str: # pragma: no cover class DateFieldsModelNoSubclass(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="test_date_models", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="test_date_models") date_id: int = ormar.Integer(primary_key=True) created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) @@ -48,10 +39,8 @@ class DateFieldsModelNoSubclass(ormar.Model): class DateFieldsModel(ormar.Model): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( abstract=True, - metadata=metadata, - database=db, constraints=[ ormar.fields.constraints.UniqueColumns( "creation_date", @@ -72,7 +61,7 @@ class DateFieldsModel(ormar.Model): class Category(DateFieldsModel, AuditModel): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( tablename="categories", constraints=[ormar.fields.constraints.UniqueColumns("name", "code")], ) @@ -91,7 +80,7 @@ def audit(self) -> str: class Subject(DateFieldsModel): - ormar_config = ormar.OrmarConfig() + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -99,21 +88,14 @@ class Subject(DateFieldsModel): class Person(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Car(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract=True, - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(abstract=True) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) @@ -129,22 +111,14 @@ class Truck(Car): class Bus(Car): - ormar_config = ormar.OrmarConfig( - tablename="buses", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="buses") owner: Person = ormar.ForeignKey(Person, related_name="buses") max_persons: int = ormar.Integer() class Car2(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract=True, - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(abstract=True) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) @@ -154,13 +128,13 @@ class Car2(ormar.Model): class Truck2(Car2): - ormar_config = ormar.OrmarConfig(tablename="trucks2") + ormar_config = base_ormar_config.copy(tablename="trucks2") max_capacity: int = ormar.Integer() class Bus2(Car2): - ormar_config = ormar.OrmarConfig(tablename="buses2") + ormar_config = base_ormar_config.copy(tablename="buses2") max_persons: int = ormar.Integer() @@ -169,11 +143,7 @@ class ImmutablePerson(Person): model_config = dict(frozen=True, validate_assignment=False) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_init_of_abstract_model() -> None: @@ -193,11 +163,7 @@ class Bus3(Car2): # pragma: no cover def test_field_redefining_in_concrete_models() -> None: class RedefinedField(DateFieldsModel): - ormar_config = ormar.OrmarConfig( - tablename="redefines", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="redefines") id: int = ormar.Integer(primary_key=True) created_date: str = ormar.String( @@ -221,11 +187,7 @@ def test_model_subclassing_that_redefines_constraints_column_names() -> None: with pytest.raises(ModelDefinitionError): class WrongField2(DateFieldsModel): # pragma: no cover - ormar_config = ormar.OrmarConfig( - tablename="wrongs", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="wrongs") id: int = ormar.Integer(primary_key=True) created_date: str = ormar.String(max_length=200) # type: ignore @@ -235,18 +197,14 @@ def test_model_subclassing_non_abstract_raises_error() -> None: with pytest.raises(ModelDefinitionError): class WrongField2(DateFieldsModelNoSubclass): # pragma: no cover - ormar_config = ormar.OrmarConfig( - tablename="wrongs", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="wrongs") id: int = ormar.Integer(primary_key=True) def test_params_are_inherited() -> None: - assert Category.ormar_config.metadata == metadata - assert Category.ormar_config.database == db + assert Category.ormar_config.metadata == base_ormar_config.metadata + assert Category.ormar_config.database == base_ormar_config.database assert len(Category.ormar_config.property_fields) == 2 constraints = Counter(map(lambda c: type(c), Category.ormar_config.constraints)) @@ -265,8 +223,8 @@ def round_date_to_seconds( @pytest.mark.asyncio async def test_fields_inherited_from_mixin() -> None: - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): cat = await Category( name="Foo", code=123, created_by="Sam", updated_by="Max" ).save() @@ -282,6 +240,8 @@ async def test_fields_inherited_from_mixin() -> None: assert all( field in Subject.ormar_config.model_fields for field in mixin_columns ) + assert cat.code_name == "123:Foo" + assert cat.audit == "Sam Max" assert sub.created_date is not None assert sub.updated_date is not None @@ -293,7 +253,7 @@ async def test_fields_inherited_from_mixin() -> None: for field in mixin2_columns ) - inspector = sa.inspect(engine) + inspector = sa.inspect(base_ormar_config.engine) assert "categories" in inspector.get_table_names() table_columns = [x.get("name") for x in inspector.get_columns("categories")] assert all( @@ -342,8 +302,8 @@ async def test_fields_inherited_from_mixin() -> None: @pytest.mark.asyncio async def test_inheritance_with_relation() -> None: - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): sam = await Person(name="Sam").save() joe = await Person(name="Joe").save() await Truck( @@ -391,8 +351,8 @@ async def test_inheritance_with_relation() -> None: @pytest.mark.asyncio async def test_inheritance_with_multi_relation() -> None: - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): sam = await Person(name="Sam").save() joe = await Person(name="Joe").save() alex = await Person(name="Alex").save() diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py index 46f7b9062..923c0c897 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py @@ -1,17 +1,15 @@ import datetime from typing import Optional -import databases import ormar import pytest import sqlalchemy as sa -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sa.MetaData() -db = databases.Database(DATABASE_URL) -engine = create_engine(DATABASE_URL) + +base_ormar_config = create_config() class AuditMixin: @@ -25,11 +23,7 @@ class DateFieldsMixins: class Category(ormar.Model, DateFieldsMixins, AuditMixin): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -37,31 +31,19 @@ class Category(ormar.Model, DateFieldsMixins, AuditMixin): class Subject(ormar.Model, DateFieldsMixins): - ormar_config = ormar.OrmarConfig( - tablename="subjects", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="subjects") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) category: Optional[Category] = ormar.ForeignKey(Category) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_field_redefining() -> None: class RedefinedField(ormar.Model, DateFieldsMixins): - ormar_config = ormar.OrmarConfig( - tablename="redefined", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="redefined") id: int = ormar.Integer(primary_key=True) created_date: datetime.datetime = ormar.DateTime(name="creation_date") @@ -81,11 +63,7 @@ class RedefinedField(ormar.Model, DateFieldsMixins): def test_field_redefining_in_second() -> None: class RedefinedField2(ormar.Model, DateFieldsMixins): - ormar_config = ormar.OrmarConfig( - tablename="redefines2", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="redefines2") id: int = ormar.Integer(primary_key=True) created_date: str = ormar.String( @@ -119,8 +97,8 @@ def round_date_to_seconds( @pytest.mark.asyncio async def test_fields_inherited_from_mixin() -> None: - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): cat = await Category( name="Foo", code=123, created_by="Sam", updated_by="Max" ).save() @@ -146,7 +124,7 @@ async def test_fields_inherited_from_mixin() -> None: for field in mixin2_columns ) - inspector = sa.inspect(engine) + inspector = sa.inspect(base_ormar_config.engine) assert "categories" in inspector.get_table_names() table_columns = [x.get("name") for x in inspector.get_columns("categories")] assert all(col in table_columns for col in mixin_columns + mixin2_columns) diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py index a9d0cf166..f8d9834ee 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py @@ -1,18 +1,15 @@ -import databases import ormar -import pytest -import sqlalchemy -import sqlalchemy as sa from pydantic import computed_field -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sa.MetaData() -database = databases.Database(DATABASE_URL) + +base_ormar_config = create_config() class BaseFoo(ormar.Model): - ormar_config = ormar.OrmarConfig(abstract=True) + ormar_config = base_ormar_config.copy(abstract=True) name: str = ormar.String(max_length=100) @@ -22,10 +19,7 @@ def prefixed_name(self) -> str: class Foo(BaseFoo): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy() @computed_field def double_prefixed_name(self) -> str: @@ -35,10 +29,7 @@ def double_prefixed_name(self) -> str: class Bar(BaseFoo): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy() @computed_field def prefixed_name(self) -> str: @@ -47,13 +38,7 @@ def prefixed_name(self) -> str: id: int = ormar.Integer(primary_key=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_property_fields_are_inherited(): diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py index 27db40dee..900b0ffe3 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py @@ -1,21 +1,14 @@ import datetime import uuid -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL) - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class BaseModel(ormar.Model): @@ -35,13 +28,7 @@ class Member(BaseModel): last_name: str = ormar.String(max_length=50) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_model_structure(): @@ -58,6 +45,6 @@ def test_model_structure(): @pytest.mark.asyncio async def test_fields_inherited_with_default(): - async with database: + async with base_ormar_config.database: await Member(first_name="foo", last_name="bar").save() await Member.objects.create(first_name="foo", last_name="bar") diff --git a/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py b/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py index a038fab5c..44a75791d 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py @@ -5,18 +5,15 @@ import pytest import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL) + +base_ormar_config = create_config() class TableBase(ormar.Model): - ormar_config = ormar.OrmarConfig( - abstract=True, - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(abstract=True) id: int = ormar.Integer(primary_key=True) created_by: str = ormar.String(max_length=20, default="test") @@ -28,7 +25,7 @@ class TableBase(ormar.Model): class NationBase(ormar.Model): - ormar_config = ormar.OrmarConfig(abstract=True) + ormar_config = base_ormar_config.copy(abstract=True) name: str = ormar.String(max_length=50) alpha2_code: str = ormar.String(max_length=2) @@ -37,21 +34,15 @@ class NationBase(ormar.Model): class Nation(NationBase, TableBase): - ormar_config = ormar.OrmarConfig() + ormar_config = base_ormar_config.copy() -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_model_is_not_abstract_by_default(): - async with database: + async with base_ormar_config.database: sweden = await Nation( name="Sweden", alpha2_code="SE", region="Europe", subregion="Scandinavia" ).save() diff --git a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py index 08e99c9fc..87a2b7bad 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py @@ -1,17 +1,10 @@ -import databases import ormar -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Library(ormar.Model): @@ -46,6 +39,9 @@ class TicketPackage(ormar.Model): package: Package = ormar.ForeignKey(Package, related_name="tickets") +create_test_database = init_tests(base_ormar_config) + + def test_have_proper_children(): TicketPackageOut = TicketPackage.get_pydantic(exclude={"ticket"}) assert "package" in TicketPackageOut.model_fields diff --git a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py index b53aa5676..f4661338d 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py +++ b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py @@ -1,25 +1,14 @@ -import databases import ormar -import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL) - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class NewTestModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() a: int = ormar.Integer(primary_key=True) b: str = ormar.String(max_length=1) @@ -29,13 +18,7 @@ class NewTestModel(ormar.Model): f: str = ormar.String(max_length=1) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_model_field_order(): diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py index b09e2740a..7afb2cb77 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py @@ -1,25 +1,18 @@ import enum -import databases import ormar import pytest -import sqlalchemy from pydantic import ValidationError, field_validator -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL) - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class BaseModel(ormar.Model): - ormar_config = ormar.OrmarConfig(abstract=True) + ormar_config = base_ormar_config.copy(abstract=True) id: int = ormar.Integer(primary_key=True) str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) @@ -46,6 +39,9 @@ class ModelExample(BaseModel): ModelExampleCreate = ModelExample.get_pydantic(exclude={"id"}) +create_test_database = init_tests(base_ormar_config) + + def test_ormar_validator(): ModelExample(str_field="a aaaaaa", enum_field="A") with pytest.raises(ValidationError) as e: diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py index e2ffe047f..96ebc17c6 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py @@ -1,21 +1,14 @@ import enum -import databases import ormar import pytest -import sqlalchemy from pydantic import ValidationError, field_validator -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL) - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class EnumExample(str, enum.Enum): @@ -25,11 +18,7 @@ class EnumExample(str, enum.Enum): class ModelExample(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - tablename="examples", - ) + ormar_config = base_ormar_config.copy(tablename="examples") id: int = ormar.Integer(primary_key=True) str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) @@ -45,6 +34,9 @@ def validate_str_field(cls, v): ModelExampleCreate = ModelExample.get_pydantic(exclude={"id"}) +create_test_database = init_tests(base_ormar_config) + + def test_ormar_validator(): ModelExample(str_field="a aaaaaa", enum_field="A") with pytest.raises(ValidationError) as e: diff --git a/tests/test_meta_constraints/test_check_constraints.py b/tests/test_meta_constraints/test_check_constraints.py index c55a4d9f5..4af656464 100644 --- a/tests/test_meta_constraints/test_check_constraints.py +++ b/tests/test_meta_constraints/test_check_constraints.py @@ -1,22 +1,19 @@ import sqlite3 import asyncpg # type: ignore -import databases import ormar.fields.constraints import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Product(ormar.Model): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( tablename="products", - metadata=metadata, - database=database, constraints=[ ormar.fields.constraints.CheckColumns("inventory > buffer"), ], @@ -29,20 +26,14 @@ class Product(ormar.Model): buffer: int = ormar.Integer() -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_check_columns_exclude_mysql(): if Product.ormar_config.database._backend._dialect.name != "mysql": - async with database: # pragma: no cover - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: # pragma: no cover + async with base_ormar_config.database.transaction(force_rollback=True): await Product.objects.create( name="Mars", company="Nestle", inventory=100, buffer=10 ) diff --git a/tests/test_meta_constraints/test_index_constraints.py b/tests/test_meta_constraints/test_index_constraints.py index 056b90204..291839628 100644 --- a/tests/test_meta_constraints/test_index_constraints.py +++ b/tests/test_meta_constraints/test_index_constraints.py @@ -1,19 +1,16 @@ -import databases import ormar.fields.constraints import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Product(ormar.Model): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( tablename="products", - metadata=metadata, - database=database, constraints=[ ormar.fields.constraints.IndexColumns("company", "name", name="my_index"), ormar.fields.constraints.IndexColumns("location", "company_type"), @@ -27,13 +24,7 @@ class Product(ormar.Model): company_type: str = ormar.String(max_length=200) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_table_structure(): @@ -52,8 +43,8 @@ def test_table_structure(): @pytest.mark.asyncio async def test_index_is_not_unique(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await Product.objects.create( name="Cookies", company="Nestle", location="A", company_type="B" ) diff --git a/tests/test_meta_constraints/test_unique_constraints.py b/tests/test_meta_constraints/test_unique_constraints.py index 91623c935..64da9ad5b 100644 --- a/tests/test_meta_constraints/test_unique_constraints.py +++ b/tests/test_meta_constraints/test_unique_constraints.py @@ -1,23 +1,20 @@ import sqlite3 import asyncpg # type: ignore -import databases import ormar.fields.constraints import pymysql import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Product(ormar.Model): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( tablename="products", - metadata=metadata, - database=database, constraints=[ormar.fields.constraints.UniqueColumns("name", "company")], ) @@ -26,19 +23,13 @@ class Product(ormar.Model): company: str = ormar.String(max_length=200) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_unique_columns(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await Product.objects.create(name="Cookies", company="Nestle") await Product.objects.create(name="Mars", company="Mars") await Product.objects.create(name="Mars", company="Nestle") diff --git a/tests/test_model_definition/test_aliases.py b/tests/test_model_definition/test_aliases.py index 230e3d58d..13fbb530d 100644 --- a/tests/test_model_definition/test_aliases.py +++ b/tests/test_model_definition/test_aliases.py @@ -1,22 +1,17 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Child(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="children", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="children") id: int = ormar.Integer(name="child_id", primary_key=True) first_name: str = ormar.String(name="fname", max_length=100) @@ -25,11 +20,7 @@ class Child(ormar.Model): class Artist(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="artists", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="artists") id: int = ormar.Integer(name="artist_id", primary_key=True) first_name: str = ormar.String(name="fname", max_length=100) @@ -39,24 +30,14 @@ class Artist(ormar.Model): class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="music_albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="music_albums") id: int = ormar.Integer(name="album_id", primary_key=True) name: str = ormar.String(name="album_name", max_length=100) artist: Optional[Artist] = ormar.ForeignKey(Artist, name="artist_id") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_table_structure(): @@ -69,8 +50,8 @@ def test_table_structure(): @pytest.mark.asyncio async def test_working_with_aliases(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): artist = await Artist.objects.create( first_name="Ted", last_name="Mosbey", born_year=1975 ) @@ -127,7 +108,7 @@ async def test_working_with_aliases(): @pytest.mark.asyncio async def test_bulk_operations_and_fields(): - async with database: + async with base_ormar_config.database: d1 = Child(first_name="Daughter", last_name="1", born_year=1990) d2 = Child(first_name="Daughter", last_name="2", born_year=1991) await Child.objects.bulk_create([d1, d2]) @@ -158,8 +139,8 @@ async def test_bulk_operations_and_fields(): @pytest.mark.asyncio async def test_working_with_aliases_get_or_create(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): artist, created = await Artist.objects.get_or_create( first_name="Teddy", last_name="Bear", born_year=2020 ) diff --git a/tests/test_model_definition/test_columns.py b/tests/test_model_definition/test_columns.py index 85eae2a97..94b24f862 100644 --- a/tests/test_model_definition/test_columns.py +++ b/tests/test_model_definition/test_columns.py @@ -1,17 +1,16 @@ import datetime from enum import Enum -import databases import ormar import pydantic import pytest -import sqlalchemy from ormar import ModelDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config(force_rollback=True) def time(): @@ -24,11 +23,7 @@ class MyEnum(Enum): class Example(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="example", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="example") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, default="aaa") @@ -42,22 +37,13 @@ class Example(ormar.Model): class EnumExample(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="enum_example", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="enum_example") id: int = ormar.Integer(primary_key=True) size: MyEnum = ormar.Enum(enum_class=MyEnum, default=MyEnum.SMALL) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_proper_enum_column_type(): @@ -75,7 +61,7 @@ class WrongEnum(Enum): @pytest.mark.asyncio async def test_enum_bulk_operations(): - async with database: + async with base_ormar_config.database: examples = [EnumExample(), EnumExample()] await EnumExample.objects.bulk_create(examples) @@ -92,7 +78,7 @@ async def test_enum_bulk_operations(): @pytest.mark.asyncio async def test_enum_filter(): - async with database: + async with base_ormar_config.database: examples = [EnumExample(), EnumExample(size=MyEnum.BIG)] await EnumExample.objects.bulk_create(examples) @@ -105,7 +91,7 @@ async def test_enum_filter(): @pytest.mark.asyncio async def test_model_crud(): - async with database: + async with base_ormar_config.database: example = Example() await example.save() @@ -133,15 +119,11 @@ async def test_model_crud(): @pytest.mark.asyncio async def test_invalid_enum_field() -> None: - async with database: + async with base_ormar_config.database: with pytest.raises(ModelDefinitionError): class Example2(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="example", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="example2") id: int = ormar.Integer(primary_key=True) size: MyEnum = ormar.Enum(enum_class=[]) # type: ignore diff --git a/tests/test_model_definition/test_create_uses_init_for_consistency.py b/tests/test_model_definition/test_create_uses_init_for_consistency.py index 6142bfce9..736248008 100644 --- a/tests/test_model_definition/test_create_uses_init_for_consistency.py +++ b/tests/test_model_definition/test_create_uses_init_for_consistency.py @@ -1,16 +1,15 @@ import uuid from typing import ClassVar -import databases import ormar import pytest -import sqlalchemy from pydantic import model_validator -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Mol(ormar.Model): @@ -19,9 +18,7 @@ class Mol(ormar.Model): "12345678-abcd-1234-abcd-123456789abc" ) - ormar_config = ormar.OrmarConfig( - database=database, metadata=metadata, tablename="mols" - ) + ormar_config = base_ormar_config.copy(tablename="mols") id: uuid.UUID = ormar.UUID(primary_key=True, index=True, uuid_format="hex") smiles: str = ormar.String(nullable=False, unique=True, max_length=256) @@ -43,17 +40,12 @@ def uuid(cls, smiles): return id_, smiles -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_json_column(): - async with database: + async with base_ormar_config.database: await Mol.objects.create(smiles="Cc1ccccc1") count = await Mol.objects.count() assert count == 1 diff --git a/tests/test_model_definition/test_dates_with_timezone.py b/tests/test_model_definition/test_dates_with_timezone.py index a524938c9..954ca350e 100644 --- a/tests/test_model_definition/test_dates_with_timezone.py +++ b/tests/test_model_definition/test_dates_with_timezone.py @@ -1,21 +1,17 @@ from datetime import date, datetime, time, timedelta, timezone -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class DateFieldsModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) created_date: datetime = ormar.DateTime( @@ -29,30 +25,21 @@ class DateFieldsModel(ormar.Model): class SampleModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) updated_at: datetime = ormar.DateTime() class TimeModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) elapsed: time = ormar.Time() class DateModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) creation_date: date = ormar.Date() @@ -62,23 +49,15 @@ class MyModel(ormar.Model): id: int = ormar.Integer(primary_key=True) created_at: datetime = ormar.DateTime(timezone=True, nullable=False) - ormar_config = ormar.OrmarConfig( - tablename="mymodels", metadata=metadata, database=database - ) + ormar_config = base_ormar_config.copy(tablename="mymodels") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_model_crud_with_timezone(): - async with database: + async with base_ormar_config.database: datemodel = await DateFieldsModel().save() assert datemodel.created_date is not None assert datemodel.updated_date is not None @@ -86,7 +65,7 @@ async def test_model_crud_with_timezone(): @pytest.mark.asyncio async def test_query_with_datetime_in_filter(): - async with database: + async with base_ormar_config.database: creation_dt = datetime(2021, 5, 18, 0, 0, 0, 0) sample = await SampleModel.objects.create(updated_at=creation_dt) @@ -100,7 +79,7 @@ async def test_query_with_datetime_in_filter(): @pytest.mark.asyncio async def test_query_with_date_in_filter(): - async with database: + async with base_ormar_config.database: sample = await TimeModel.objects.create(elapsed=time(0, 20, 20)) await TimeModel.objects.create(elapsed=time(0, 12, 0)) await TimeModel.objects.create(elapsed=time(0, 19, 55)) @@ -116,7 +95,7 @@ async def test_query_with_date_in_filter(): @pytest.mark.asyncio async def test_query_with_time_in_filter(): - async with database: + async with base_ormar_config.database: await DateModel.objects.create(creation_date=date(2021, 5, 18)) sample2 = await DateModel.objects.create(creation_date=date(2021, 5, 19)) sample3 = await DateModel.objects.create(creation_date=date(2021, 5, 20)) @@ -132,7 +111,7 @@ async def test_query_with_time_in_filter(): @pytest.mark.asyncio async def test_filtering_by_timezone_with_timedelta(): - async with database: + async with base_ormar_config.database: now_utc = datetime.now(timezone.utc) object = MyModel(created_at=now_utc) await object.save() diff --git a/tests/test_model_definition/test_equality_and_hash.py b/tests/test_model_definition/test_equality_and_hash.py index e8b52a61b..0d46dadf0 100644 --- a/tests/test_model_definition/test_equality_and_hash.py +++ b/tests/test_model_definition/test_equality_and_hash.py @@ -1,38 +1,27 @@ # type: ignore -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Song(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="songs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="songs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_equality(): - async with database: + async with base_ormar_config.database: song1 = await Song.objects.create(name="Song") song2 = await Song.objects.create(name="Song") song3 = Song(name="Song") @@ -49,7 +38,7 @@ async def test_equality(): @pytest.mark.asyncio async def test_hash_doesnt_change_with_fields_if_pk(): - async with database: + async with base_ormar_config.database: song1 = await Song.objects.create(name="Song") prev_hash = hash(song1) @@ -59,7 +48,7 @@ async def test_hash_doesnt_change_with_fields_if_pk(): @pytest.mark.asyncio async def test_hash_changes_with_fields_if_no_pk(): - async with database: + async with base_ormar_config.database: song1 = Song(name="Song") prev_hash = hash(song1) diff --git a/tests/test_model_definition/test_extra_ignore_parameter.py b/tests/test_model_definition/test_extra_ignore_parameter.py index 9726db449..7f20cc503 100644 --- a/tests/test_model_definition/test_extra_ignore_parameter.py +++ b/tests/test_model_definition/test_extra_ignore_parameter.py @@ -1,19 +1,16 @@ -import databases import ormar -import sqlalchemy from ormar import Extra -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config(force_rollback=True) class Child(ormar.Model): - ormar_config = ormar.OrmarConfig( + ormar_config = base_ormar_config.copy( tablename="children", - metadata=metadata, - database=database, extra=Extra.ignore, ) @@ -22,6 +19,9 @@ class Child(ormar.Model): last_name: str = ormar.String(name="lname", max_length=100) +create_test_database = init_tests(base_ormar_config) + + def test_allow_extra_parameter(): child = Child(first_name="Test", last_name="Name", extra_param="Unexpected") assert child.first_name == "Test" diff --git a/tests/test_model_definition/test_fields_access.py b/tests/test_model_definition/test_fields_access.py index a4c34e534..c457f1438 100644 --- a/tests/test_model_definition/test_fields_access.py +++ b/tests/test_model_definition/test_fields_access.py @@ -4,16 +4,11 @@ import sqlalchemy from ormar import BaseField -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class PriceList(ormar.Model): @@ -40,13 +35,7 @@ class Product(ormar.Model): category = ormar.ForeignKey(Category) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_fields_access(): @@ -189,8 +178,8 @@ def test_combining_groups_together(): @pytest.mark.asyncio async def test_filtering_by_field_access(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): category = await Category(name="Toys").save() product2 = await Product( name="My Little Pony", rating=3.8, category=category diff --git a/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py b/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py index 9df1ef505..5ebc7f9bb 100644 --- a/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py +++ b/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py @@ -1,21 +1,14 @@ import uuid from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class PageLink(ormar.Model): @@ -52,18 +45,13 @@ class Course(ormar.Model): department: Optional[Department] = ormar.ForeignKey(Department) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_pass_int_values_as_fk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): link = await PageLink(id=1, value="test", country="USA").save() await Post.objects.create(title="My post", link=link.id) post_check = await Post.objects.select_related("link").get() @@ -72,7 +60,7 @@ async def test_pass_int_values_as_fk(): @pytest.mark.asyncio async def test_pass_uuid_value_as_fk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): dept = await Department(name="Department test").save() await Course(name="Test course", department=dept.id).save() diff --git a/tests/test_model_definition/test_iterate.py b/tests/test_model_definition/test_iterate.py index 2dcad639e..c5a9f78f0 100644 --- a/tests/test_model_definition/test_iterate.py +++ b/tests/test_model_definition/test_iterate.py @@ -1,34 +1,25 @@ import uuid -import databases import ormar import pytest -import sqlalchemy from ormar.exceptions import QueryDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users3", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users3") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="") class User2(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users4", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users4") id: uuid.UUID = ormar.UUID( uuid_format="string", primary_key=True, default=uuid.uuid4 @@ -37,11 +28,7 @@ class User2(ormar.Model): class Task(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tasks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tasks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="") @@ -49,11 +36,7 @@ class Task(ormar.Model): class Task2(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tasks2", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tasks2") id: uuid.UUID = ormar.UUID( uuid_format="string", primary_key=True, default=uuid.uuid4 @@ -62,27 +45,21 @@ class Task2(ormar.Model): user: User2 = ormar.ForeignKey(to=User2) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_empty_result(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): async for user in User.objects.iterate(): pass # pragma: no cover @pytest.mark.asyncio async def test_model_iterator(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User.objects.create(name="Tom") jane = await User.objects.create(name="Jane") lucy = await User.objects.create(name="Lucy") @@ -93,8 +70,8 @@ async def test_model_iterator(): @pytest.mark.asyncio async def test_model_iterator_filter(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User.objects.create(name="Tom") await User.objects.create(name="Jane") await User.objects.create(name="Lucy") @@ -105,8 +82,8 @@ async def test_model_iterator_filter(): @pytest.mark.asyncio async def test_model_iterator_relations(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User.objects.create(name="Tom") jane = await User.objects.create(name="Jane") lucy = await User.objects.create(name="Lucy") @@ -125,8 +102,8 @@ async def test_model_iterator_relations(): @pytest.mark.asyncio async def test_model_iterator_relations_queryset_proxy(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User.objects.create(name="Tom") jane = await User.objects.create(name="Jane") @@ -151,8 +128,8 @@ async def test_model_iterator_relations_queryset_proxy(): @pytest.mark.asyncio async def test_model_iterator_uneven_number_of_relations(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User.objects.create(name="Tom") jane = await User.objects.create(name="Jane") lucy = await User.objects.create(name="Lucy") @@ -173,8 +150,8 @@ async def test_model_iterator_uneven_number_of_relations(): @pytest.mark.asyncio async def test_model_iterator_uuid_pk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User2.objects.create(name="Tom") jane = await User2.objects.create(name="Jane") lucy = await User2.objects.create(name="Lucy") @@ -185,8 +162,8 @@ async def test_model_iterator_uuid_pk(): @pytest.mark.asyncio async def test_model_iterator_filter_uuid_pk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User2.objects.create(name="Tom") await User2.objects.create(name="Jane") await User2.objects.create(name="Lucy") @@ -197,8 +174,8 @@ async def test_model_iterator_filter_uuid_pk(): @pytest.mark.asyncio async def test_model_iterator_relations_uuid_pk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User2.objects.create(name="Tom") jane = await User2.objects.create(name="Jane") lucy = await User2.objects.create(name="Lucy") @@ -217,8 +194,8 @@ async def test_model_iterator_relations_uuid_pk(): @pytest.mark.asyncio async def test_model_iterator_relations_queryset_proxy_uuid_pk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User2.objects.create(name="Tom") jane = await User2.objects.create(name="Jane") @@ -243,8 +220,8 @@ async def test_model_iterator_relations_queryset_proxy_uuid_pk(): @pytest.mark.asyncio async def test_model_iterator_uneven_number_of_relations_uuid_pk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User2.objects.create(name="Tom") jane = await User2.objects.create(name="Jane") lucy = await User2.objects.create(name="Lucy") @@ -267,7 +244,7 @@ async def test_model_iterator_uneven_number_of_relations_uuid_pk(): @pytest.mark.asyncio async def test_model_iterator_with_prefetch_raises_error(): - async with database: + async with base_ormar_config.database: with pytest.raises(QueryDefinitionError): async for user in User.objects.prefetch_related(User.tasks).iterate(): pass # pragma: no cover diff --git a/tests/test_model_definition/test_model_construct.py b/tests/test_model_definition/test_model_construct.py index 1ef8ec559..85ad4101d 100644 --- a/tests/test_model_definition/test_model_construct.py +++ b/tests/test_model_definition/test_model_construct.py @@ -1,41 +1,28 @@ from typing import List -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class NickNames(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") class NicksHq(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks_x_hq", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks_x_hq") class HQ(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="hqs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="hqs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -43,11 +30,7 @@ class HQ(ormar.Model): class Company(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="companies", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -55,19 +38,13 @@ class Company(ormar.Model): hq: HQ = ormar.ForeignKey(HQ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_construct_with_empty_relation(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await HQ.objects.create(name="Main") comp = Company(name="Banzai", hq=None, founded=1988) comp2 = Company.model_construct( @@ -78,8 +55,8 @@ async def test_construct_with_empty_relation(): @pytest.mark.asyncio async def test_init_and_construct_has_same_effect(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): hq = await HQ.objects.create(name="Main") comp = Company(name="Banzai", hq=hq, founded=1988) comp2 = Company.model_construct(**dict(name="Banzai", hq=hq, founded=1988)) @@ -93,8 +70,8 @@ async def test_init_and_construct_has_same_effect(): @pytest.mark.asyncio async def test_init_and_construct_has_same_effect_with_m2m(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): n1 = await NickNames(name="test").save() n2 = await NickNames(name="test2").save() hq = HQ(name="Main", nicks=[n1, n2]) diff --git a/tests/test_model_definition/test_model_definition.py b/tests/test_model_definition/test_model_definition.py index 0393d5111..7d841bf18 100644 --- a/tests/test_model_definition/test_model_definition.py +++ b/tests/test_model_definition/test_model_definition.py @@ -3,7 +3,6 @@ import decimal import typing -import databases import ormar import pydantic import pytest @@ -11,18 +10,15 @@ from ormar.exceptions import ModelDefinitionError from ormar.models import Model -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) + +base_ormar_config = create_config() class ExampleModel(Model): - ormar_config = ormar.OrmarConfig( - tablename="example", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="example") test: int = ormar.Integer(primary_key=True) test_string: str = ormar.String(max_length=250) @@ -53,22 +49,13 @@ class ExampleModel(Model): class ExampleModel2(Model): - ormar_config = ormar.OrmarConfig( - tablename="examples", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="example2") test: int = ormar.Integer(primary_key=True) test_string: str = ormar.String(max_length=250) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.fixture() @@ -117,7 +104,7 @@ def test_missing_metadata(): class JsonSample2(ormar.Model): ormar_config = ormar.OrmarConfig( tablename="jsons2", - database=database, + database=base_ormar_config.database, ) id: int = ormar.Integer(primary_key=True) @@ -176,11 +163,7 @@ def test_no_pk_in_model_definition(): with pytest.raises(ModelDefinitionError): # type: ignore class ExampleModel2(Model): # type: ignore - ormar_config = ormar.OrmarConfig( - tablename="example2", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="example2") test_string: str = ormar.String(max_length=250) # type: ignore @@ -191,11 +174,7 @@ def test_two_pks_in_model_definition(): @typing.no_type_check class ExampleModel2(Model): - ormar_config = ormar.OrmarConfig( - tablename="example3", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="example3") id: int = ormar.Integer(primary_key=True) test_string: str = ormar.String(max_length=250, primary_key=True) @@ -206,11 +185,7 @@ def test_decimal_error_in_model_definition(): with pytest.raises(ModelDefinitionError): class ExampleModel2(Model): - ormar_config = ormar.OrmarConfig( - tablename="example5", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="example5") test: decimal.Decimal = ormar.Decimal(primary_key=True) @@ -220,11 +195,7 @@ def test_binary_error_without_length_model_definition(): with pytest.raises(ModelDefinitionError): class ExampleModel2(Model): - ormar_config = ormar.OrmarConfig( - tablename="example6", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="example6") test: bytes = ormar.LargeBinary(primary_key=True, max_length=-1) @@ -234,11 +205,7 @@ def test_string_error_in_model_definition(): with pytest.raises(ModelDefinitionError): class ExampleModel2(Model): - ormar_config = ormar.OrmarConfig( - tablename="example6", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="example6") test: str = ormar.String(primary_key=True, max_length=0) diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index 1f099100e..951edafd1 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -5,25 +5,21 @@ import uuid from enum import Enum -import databases import ormar import pydantic import pytest import sqlalchemy from ormar.exceptions import ModelError, NoMatch, QueryDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class JsonSample(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="jsons", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="jsons") id: int = ormar.Integer(primary_key=True) test_json = ormar.JSON(nullable=True) @@ -34,11 +30,7 @@ class JsonSample(ormar.Model): class LargeBinarySample(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="my_bolbs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="my_bolbs") id: int = ormar.Integer(primary_key=True) test_binary: bytes = ormar.LargeBinary(max_length=100000) @@ -49,11 +41,7 @@ class LargeBinarySample(ormar.Model): class LargeBinaryStr(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="my_str_blobs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="my_str_bolbs") id: int = ormar.Integer(primary_key=True) test_binary: str = ormar.LargeBinary( @@ -62,11 +50,7 @@ class LargeBinaryStr(ormar.Model): class LargeBinaryNullableStr(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="my_str_blobs2", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="my_str_bolbs2") id: int = ormar.Integer(primary_key=True) test_binary: str = ormar.LargeBinary( @@ -78,22 +62,14 @@ class LargeBinaryNullableStr(ormar.Model): class UUIDSample(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="uuids", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="uuids") id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) test_text: str = ormar.Text() class UUIDSample2(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="uuids2", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="uuids2") id: uuid.UUID = ormar.UUID( primary_key=True, default=uuid.uuid4, uuid_format="string" @@ -102,33 +78,21 @@ class UUIDSample2(ormar.Model): class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="") class User2(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users2", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users2") id: str = ormar.String(primary_key=True, max_length=100) name: str = ormar.String(max_length=100, default="") class Product(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="product", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="product") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -152,11 +116,7 @@ class CountryCodeEnum(int, Enum): class Country(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="country", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="country") id: int = ormar.Integer(primary_key=True) name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, default="Canada") @@ -165,34 +125,20 @@ class Country(ormar.Model): class NullableCountry(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="country2", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="country2") id: int = ormar.Integer(primary_key=True) name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, nullable=True) class NotNullableCountry(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="country3", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="country3") id: int = ormar.Integer(primary_key=True) name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, nullable=False) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_model_class(): @@ -219,8 +165,8 @@ def test_model_pk(): @pytest.mark.asyncio async def test_json_column(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await JsonSample.objects.create(test_json=dict(aa=12)) await JsonSample.objects.create(test_json='{"aa": 12}') @@ -235,8 +181,8 @@ async def test_json_column(): @pytest.mark.asyncio async def test_binary_column(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await LargeBinarySample.objects.create(test_binary=blob) await LargeBinarySample.objects.create(test_binary=blob2) @@ -251,8 +197,8 @@ async def test_binary_column(): @pytest.mark.asyncio async def test_binary_str_column(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await LargeBinaryStr(test_binary=blob3).save() await LargeBinaryStr.objects.create(test_binary=blob4) @@ -267,8 +213,8 @@ async def test_binary_str_column(): @pytest.mark.asyncio async def test_binary_nullable_str_column(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await LargeBinaryNullableStr().save() await LargeBinaryNullableStr.objects.create() items = await LargeBinaryNullableStr.objects.all() @@ -298,8 +244,8 @@ async def test_binary_nullable_str_column(): @pytest.mark.asyncio async def test_uuid_column(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): u1 = await UUIDSample.objects.create(test_text="aa") u2 = await UUIDSample.objects.create(test_text="bb") @@ -333,8 +279,8 @@ async def test_uuid_column(): @pytest.mark.asyncio async def test_model_crud(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): users = await User.objects.all() assert users == [] @@ -360,8 +306,8 @@ async def test_model_crud(): @pytest.mark.asyncio async def test_model_get(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): with pytest.raises(ormar.NoMatch): await User.objects.get() @@ -385,8 +331,8 @@ async def test_model_get(): @pytest.mark.asyncio async def test_model_filter(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await User.objects.create(name="Tom") await User.objects.create(name="Jane") await User.objects.create(name="Lucy") @@ -441,7 +387,7 @@ async def test_model_filter(): @pytest.mark.asyncio async def test_wrong_query_contains_model(): - async with database: + async with base_ormar_config.database: with pytest.raises(QueryDefinitionError): product = Product(name="90%-Cotton", rating=2) await Product.objects.filter(name__contains=product).count() @@ -449,8 +395,8 @@ async def test_wrong_query_contains_model(): @pytest.mark.asyncio async def test_model_exists(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await User.objects.create(name="Tom") assert await User.objects.filter(name="Tom").exists() is True assert await User.objects.filter(name="Jane").exists() is False @@ -458,8 +404,8 @@ async def test_model_exists(): @pytest.mark.asyncio async def test_model_count(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await User.objects.create(name="Tom") await User.objects.create(name="Jane") await User.objects.create(name="Lucy") @@ -470,8 +416,8 @@ async def test_model_count(): @pytest.mark.asyncio async def test_model_limit(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await User.objects.create(name="Tom") await User.objects.create(name="Jane") await User.objects.create(name="Lucy") @@ -481,8 +427,8 @@ async def test_model_limit(): @pytest.mark.asyncio async def test_model_limit_with_filter(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await User.objects.create(name="Tom") await User.objects.create(name="Tom") await User.objects.create(name="Tom") @@ -494,8 +440,8 @@ async def test_model_limit_with_filter(): @pytest.mark.asyncio async def test_offset(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await User.objects.create(name="Tom") await User.objects.create(name="Jane") @@ -505,8 +451,8 @@ async def test_offset(): @pytest.mark.asyncio async def test_model_first(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): tom = await User.objects.create(name="Tom") jane = await User.objects.create(name="Jane") @@ -522,7 +468,7 @@ async def test_model_first(): @pytest.mark.asyncio async def test_model_choices(): """Test that choices work properly for various types of fields.""" - async with database: + async with base_ormar_config.database: # Test valid choices. await asyncio.gather( Country.objects.create(name="Canada", taxed=True, country_code=1), @@ -562,7 +508,7 @@ async def test_model_choices(): @pytest.mark.asyncio async def test_nullable_field_model_choices(): """Test that choices work properly for according to nullable setting""" - async with database: + async with base_ormar_config.database: c1 = await NullableCountry(name=None).save() assert c1.name is None @@ -572,8 +518,8 @@ async def test_nullable_field_model_choices(): @pytest.mark.asyncio async def test_start_and_end_filters(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await User.objects.create(name="Markos Uj") await User.objects.create(name="Maqua Bigo") await User.objects.create(name="maqo quidid") @@ -602,8 +548,8 @@ async def test_start_and_end_filters(): @pytest.mark.asyncio async def test_get_and_first(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await User.objects.create(name="Tom") await User.objects.create(name="Jane") await User.objects.create(name="Lucy") diff --git a/tests/test_model_definition/test_models_are_pickable.py b/tests/test_model_definition/test_models_are_pickable.py index 42d7adcbc..c0c90e1f0 100644 --- a/tests/test_model_definition/test_models_are_pickable.py +++ b/tests/test_model_definition/test_models_are_pickable.py @@ -1,23 +1,18 @@ import pickle from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -25,29 +20,19 @@ class User(ormar.Model): class Post(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="posts", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="posts") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) created_by: Optional[User] = ormar.ForeignKey(User) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_dumping_and_loading_model_works(): - async with database: + async with base_ormar_config.database: user = await User(name="Test", properties={"aa": "bb"}).save() post = Post(name="Test post") await user.posts.add(post) diff --git a/tests/test_model_definition/test_overwriting_pydantic_field_type.py b/tests/test_model_definition/test_overwriting_pydantic_field_type.py index cd2bb3f45..bb026415d 100644 --- a/tests/test_model_definition/test_overwriting_pydantic_field_type.py +++ b/tests/test_model_definition/test_overwriting_pydantic_field_type.py @@ -1,23 +1,18 @@ from typing import Dict, Optional -import databases import ormar import pytest -import sqlalchemy from pydantic import Json, PositiveInt, ValidationError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class OverwriteTest(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="overwrites", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="overwrites") id: int = ormar.Integer(primary_key=True) my_int: int = ormar.Integer(overwrite_pydantic_type=PositiveInt) @@ -26,13 +21,7 @@ class OverwriteTest(ormar.Model): ) # type: ignore -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_constraints(): @@ -50,7 +39,7 @@ def test_constraints(): @pytest.mark.asyncio async def test_saving(): - async with database: + async with base_ormar_config.database: await OverwriteTest(my_int=5, constraint_dict={"aa": 123}).save() test = await OverwriteTest.objects.get() diff --git a/tests/test_model_definition/test_overwriting_sql_nullable.py b/tests/test_model_definition/test_overwriting_sql_nullable.py index 08b103556..f967f05bd 100644 --- a/tests/test_model_definition/test_overwriting_sql_nullable.py +++ b/tests/test_model_definition/test_overwriting_sql_nullable.py @@ -2,23 +2,16 @@ from typing import Optional import asyncpg -import databases import ormar import pymysql import pytest -import sqlalchemy -from sqlalchemy import create_engine, text +from sqlalchemy import text -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -db = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, -) +base_ormar_config = create_config() class PrimaryModel(ormar.Model): @@ -32,17 +25,12 @@ class PrimaryModel(ormar.Model): ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_create_models(): - async with db: + async with base_ormar_config.database: primary = await PrimaryModel( name="Foo", some_text="Bar", some_other_text="Baz" ).save() diff --git a/tests/test_model_definition/test_pk_field_is_always_not_null.py b/tests/test_model_definition/test_pk_field_is_always_not_null.py index c4a37e6e4..285c82dc3 100644 --- a/tests/test_model_definition/test_pk_field_is_always_not_null.py +++ b/tests/test_model_definition/test_pk_field_is_always_not_null.py @@ -1,17 +1,10 @@ -import databases import ormar -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class AutoincrementModel(ormar.Model): @@ -32,6 +25,9 @@ class ExplicitNullableModel(ormar.Model): id: int = ormar.Integer(primary_key=True, nullable=True) +create_test_database = init_tests(base_ormar_config) + + def test_pk_field_is_not_null(): for model in [AutoincrementModel, NonAutoincrementModel, ExplicitNullableModel]: assert not model.ormar_config.table.c.get("id").nullable diff --git a/tests/test_model_definition/test_properties.py b/tests/test_model_definition/test_properties.py index 4d54bf73c..085f6e030 100644 --- a/tests/test_model_definition/test_properties.py +++ b/tests/test_model_definition/test_properties.py @@ -1,22 +1,17 @@ # type: ignore -import databases import ormar import pytest -import sqlalchemy from pydantic import PydanticUserError, computed_field -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Song(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="songs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="songs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -35,18 +30,12 @@ def sample2(self) -> str: return "sample2" -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_sort_order_on_main_model(): - async with database: + async with base_ormar_config.database: await Song.objects.create(name="Song 3", sort_order=3) await Song.objects.create(name="Song 1", sort_order=1) await Song.objects.create(name="Song 2", sort_order=2) diff --git a/tests/test_model_definition/test_pydantic_fields.py b/tests/test_model_definition/test_pydantic_fields.py index df69a6163..ff9b1e474 100644 --- a/tests/test_model_definition/test_pydantic_fields.py +++ b/tests/test_model_definition/test_pydantic_fields.py @@ -1,22 +1,16 @@ import random from typing import Optional -import databases import ormar import pytest -import sqlalchemy from pydantic import BaseModel, Field, HttpUrl from pydantic_extra_types.payment import PaymentCardNumber -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class ModelTest(ormar.Model): @@ -70,18 +64,12 @@ def __init__(self, **kwargs): pydantic_test: PydanticTest -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_working_with_pydantic_fields(): - async with database: + async with base_ormar_config.database: test = ModelTest(name="Test") assert test.name == "Test" assert test.url == "https://www.example.com" @@ -101,7 +89,7 @@ async def test_working_with_pydantic_fields(): @pytest.mark.asyncio async def test_default_factory_for_pydantic_fields(): - async with database: + async with base_ormar_config.database: test = ModelTest2(name="Test2", number="4000000000000002") assert test.name == "Test2" assert test.url == "https://www.example2.com" @@ -121,7 +109,7 @@ async def test_default_factory_for_pydantic_fields(): @pytest.mark.asyncio async def test_init_setting_for_pydantic_fields(): - async with database: + async with base_ormar_config.database: test = ModelTest3(name="Test3") assert test.name == "Test3" assert test.url == "https://www.example3.com" diff --git a/tests/test_model_definition/test_pydantic_only_fields.py b/tests/test_model_definition/test_pydantic_only_fields.py index f7c0d676a..024ecba3c 100644 --- a/tests/test_model_definition/test_pydantic_only_fields.py +++ b/tests/test_model_definition/test_pydantic_only_fields.py @@ -1,24 +1,19 @@ import datetime -import databases import ormar import pydantic import pytest -import sqlalchemy from pydantic import computed_field -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -41,19 +36,13 @@ def name40(self) -> str: return self.name + "_40" -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_pydantic_only_fields(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): album = await Album.objects.create(name="Hitchcock") assert album.pk is not None assert album.saved diff --git a/tests/test_model_definition/test_pydantic_private_attributes.py b/tests/test_model_definition/test_pydantic_private_attributes.py index c990dcf74..591dabaea 100644 --- a/tests/test_model_definition/test_pydantic_private_attributes.py +++ b/tests/test_model_definition/test_pydantic_private_attributes.py @@ -1,20 +1,13 @@ from typing import List -import databases import ormar -import sqlalchemy from pydantic import PrivateAttr -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Subscription(ormar.Model): @@ -29,6 +22,9 @@ def add_payment(self, payment: str): self._add_payments.append(payment) +create_test_database = init_tests(base_ormar_config) + + def test_private_attribute(): sub = Subscription(stripe_subscription_id="2312312sad231") sub.add_payment("test") diff --git a/tests/test_model_definition/test_save_status.py b/tests/test_model_definition/test_save_status.py index c142a5874..52f58fb32 100644 --- a/tests/test_model_definition/test_save_status.py +++ b/tests/test_model_definition/test_save_status.py @@ -1,23 +1,18 @@ from typing import List -import databases import ormar import pytest -import sqlalchemy from ormar.exceptions import ModelPersistenceError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class NickNames(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -25,19 +20,11 @@ class NickNames(ormar.Model): class NicksHq(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks_x_hq", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks_x_hq") class HQ(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="hqs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="hqs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -45,11 +32,7 @@ class HQ(ormar.Model): class Company(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="companies", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -57,19 +40,13 @@ class Company(ormar.Model): hq: HQ = ormar.ForeignKey(HQ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_instantiation_false_save_true(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): comp = Company(name="Banzai", founded=1988) assert not comp.saved await comp.save() @@ -78,8 +55,8 @@ async def test_instantiation_false_save_true(): @pytest.mark.asyncio async def test_saved_edited_not_saved(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): comp = await Company.objects.create(name="Banzai", founded=1988) assert comp.saved comp.name = "Banzai2" @@ -100,8 +77,8 @@ async def test_saved_edited_not_saved(): @pytest.mark.asyncio async def test_adding_related_gets_dirty(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): hq = await HQ.objects.create(name="Main") comp = await Company.objects.create(name="Banzai", founded=1988) assert comp.saved @@ -127,8 +104,8 @@ async def test_adding_related_gets_dirty(): @pytest.mark.asyncio async def test_adding_many_to_many_does_not_gets_dirty(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): nick1 = await NickNames.objects.create(name="Bazinga", is_lame=False) nick2 = await NickNames.objects.create(name="Bazinga2", is_lame=True) @@ -156,8 +133,8 @@ async def test_adding_many_to_many_does_not_gets_dirty(): @pytest.mark.asyncio async def test_delete(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): comp = await Company.objects.create(name="Banzai", founded=1988) assert comp.saved await comp.delete() @@ -169,8 +146,8 @@ async def test_delete(): @pytest.mark.asyncio async def test_load(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): comp = await Company.objects.create(name="Banzai", founded=1988) assert comp.saved comp.name = "AA" @@ -183,8 +160,8 @@ async def test_load(): @pytest.mark.asyncio async def test_queryset_methods(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await Company.objects.create(name="Banzai", founded=1988) await Company.objects.create(name="Yuhu", founded=1989) await Company.objects.create(name="Konono", founded=1990) @@ -226,8 +203,8 @@ async def test_queryset_methods(): @pytest.mark.asyncio async def test_bulk_methods(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): c1 = Company(name="Banzai", founded=1988) c2 = Company(name="Yuhu", founded=1989) diff --git a/tests/test_model_definition/test_saving_nullable_fields.py b/tests/test_model_definition/test_saving_nullable_fields.py index 18cb0ef29..05a2a9405 100644 --- a/tests/test_model_definition/test_saving_nullable_fields.py +++ b/tests/test_model_definition/test_saving_nullable_fields.py @@ -1,23 +1,17 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -db = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class PrimaryModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="primary_models", - ) + ormar_config = base_ormar_config.copy(tablename="primary_models") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) @@ -27,11 +21,7 @@ class PrimaryModel(ormar.Model): class SecondaryModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="secondary_models", - ) + ormar_config = base_ormar_config.copy(tablename="secondary_models") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -40,18 +30,13 @@ class SecondaryModel(ormar.Model): ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_create_models(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): primary = await PrimaryModel( name="Foo", some_text="Bar", some_other_text="Baz" ).save() diff --git a/tests/test_model_definition/test_server_default.py b/tests/test_model_definition/test_server_default.py index 45e8bf6ed..089d78463 100644 --- a/tests/test_model_definition/test_server_default.py +++ b/tests/test_model_definition/test_server_default.py @@ -1,24 +1,19 @@ import time from datetime import datetime -import databases import ormar import pytest -import sqlalchemy from sqlalchemy import func, text -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Product(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="product", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="product") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -27,13 +22,7 @@ class Product(ormar.Model): created: datetime = ormar.DateTime(server_default=func.now()) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_table_defined_properly(): @@ -46,8 +35,8 @@ def test_table_defined_properly(): @pytest.mark.asyncio async def test_model_creation(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): p1 = Product(name="Test") assert p1.created is None await p1.save() diff --git a/tests/test_model_definition/test_setting_comments_in_db.py b/tests/test_model_definition/test_setting_comments_in_db.py index 213c0cf7f..08388be5c 100644 --- a/tests/test_model_definition/test_setting_comments_in_db.py +++ b/tests/test_model_definition/test_setting_comments_in_db.py @@ -1,33 +1,22 @@ -import databases import ormar import pytest -import sqlalchemy from ormar.models import Model -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) +base_ormar_config = create_config() class Comment(Model): - ormar_config = ormar.OrmarConfig( - tablename="comments", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="comments") test: int = ormar.Integer(primary_key=True, comment="primary key of comments") test_string: str = ormar.String(max_length=250, comment="test that it works") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio diff --git a/tests/test_model_methods/test_excludes_in_load_all.py b/tests/test_model_methods/test_excludes_in_load_all.py index 62238ca5e..49811e386 100644 --- a/tests/test_model_methods/test_excludes_in_load_all.py +++ b/tests/test_model_methods/test_excludes_in_load_all.py @@ -1,20 +1,13 @@ import uuid -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config(force_rollback=True) class JimmyUser(ormar.Model): @@ -45,18 +38,12 @@ class JimmyAccount(ormar.Model): user: JimmyUser = ormar.ForeignKey(to=JimmyUser) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_excluding_one_relation(): - async with database: + async with base_ormar_config.database: user = JimmyUser() await user.save() @@ -70,7 +57,7 @@ async def test_excluding_one_relation(): @pytest.mark.asyncio async def test_excluding_other_relation(): - async with database: + async with base_ormar_config.database: user = JimmyUser() await user.save() diff --git a/tests/test_model_methods/test_load_all.py b/tests/test_model_methods/test_load_all.py index 4a9f9086f..af0452654 100644 --- a/tests/test_model_methods/test_load_all.py +++ b/tests/test_model_methods/test_load_all.py @@ -1,20 +1,13 @@ from typing import List -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Language(ormar.Model): @@ -59,19 +52,13 @@ class Company(ormar.Model): hq: HQ = ormar.ForeignKey(HQ, related_name="companies") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_load_all_fk_rel(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): hq = await HQ.objects.create(name="Main") company = await Company.objects.create(name="Banzai", founded=1988, hq=hq) @@ -90,8 +77,8 @@ async def test_load_all_fk_rel(): @pytest.mark.asyncio async def test_load_all_many_to_many(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): nick1 = await NickName.objects.create(name="BazingaO", is_lame=False) nick2 = await NickName.objects.create(name="Bazinga20", is_lame=True) hq = await HQ.objects.create(name="Main") @@ -116,8 +103,8 @@ async def test_load_all_many_to_many(): @pytest.mark.asyncio async def test_load_all_with_order(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): nick1 = await NickName.objects.create(name="Barry", is_lame=False) nick2 = await NickName.objects.create(name="Joe", is_lame=True) hq = await HQ.objects.create(name="Main") @@ -150,8 +137,8 @@ async def test_load_all_with_order(): @pytest.mark.asyncio async def test_loading_reversed_relation(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): hq = await HQ.objects.create(name="Main") await Company.objects.create(name="Banzai", founded=1988, hq=hq) @@ -166,8 +153,8 @@ async def test_loading_reversed_relation(): @pytest.mark.asyncio async def test_loading_nested(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): language = await Language.objects.create(name="English") level = await CringeLevel.objects.create(name="High", language=language) level2 = await CringeLevel.objects.create(name="Low", language=language) diff --git a/tests/test_model_methods/test_populate_default_values.py b/tests/test_model_methods/test_populate_default_values.py index 1ae5ba802..820d313c1 100644 --- a/tests/test_model_methods/test_populate_default_values.py +++ b/tests/test_model_methods/test_populate_default_values.py @@ -1,18 +1,11 @@ -import databases import ormar -import sqlalchemy from sqlalchemy import text -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Task(ormar.Model): @@ -20,7 +13,7 @@ class Task(ormar.Model): id: int = ormar.Integer(primary_key=True) name: str = ormar.String( - max_length=255, minimum=0, server_default=text("Default Name"), nullable=False + max_length=255, minimum=0, server_default=text("'Default Name'"), nullable=False ) points: int = ormar.Integer( default=0, minimum=0, server_default=text("0"), nullable=False @@ -28,6 +21,9 @@ class Task(ormar.Model): score: int = ormar.Integer(default=5) +create_test_database = init_tests(base_ormar_config) + + def test_populate_default_values(): new_kwargs = { "id": None, diff --git a/tests/test_model_methods/test_save_related.py b/tests/test_model_methods/test_save_related.py index c10f9d3e4..7201050af 100644 --- a/tests/test_model_methods/test_save_related.py +++ b/tests/test_model_methods/test_save_related.py @@ -5,29 +5,22 @@ import pytest import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class CringeLevel(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="levels", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="levels") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class NickName(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -36,19 +29,11 @@ class NickName(ormar.Model): class NicksHq(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks_x_hq", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks_x_hq") class HQ(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="hqs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="hqs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -56,11 +41,7 @@ class HQ(ormar.Model): class Company(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="companies", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -68,19 +49,13 @@ class Company(ormar.Model): hq: HQ = ormar.ForeignKey(HQ, related_name="companies") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_saving_related_fk_rel(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): hq = await HQ.objects.create(name="Main") comp = await Company.objects.create(name="Banzai", founded=1988, hq=hq) assert comp.saved @@ -107,8 +82,8 @@ async def test_saving_related_fk_rel(): @pytest.mark.asyncio async def test_saving_many_to_many(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): nick1 = await NickName.objects.create(name="BazingaO", is_lame=False) nick2 = await NickName.objects.create(name="Bazinga20", is_lame=True) @@ -149,8 +124,8 @@ async def test_saving_many_to_many(): @pytest.mark.asyncio async def test_saving_reversed_relation(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): hq = await HQ.objects.create(name="Main") await Company.objects.create(name="Banzai", founded=1988, hq=hq) @@ -190,8 +165,8 @@ async def test_saving_reversed_relation(): @pytest.mark.asyncio async def test_saving_nested(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): level = await CringeLevel.objects.create(name="High") level2 = await CringeLevel.objects.create(name="Low") nick1 = await NickName.objects.create( diff --git a/tests/test_model_methods/test_save_related_from_dict.py b/tests/test_model_methods/test_save_related_from_dict.py index 46013071f..089360ab5 100644 --- a/tests/test_model_methods/test_save_related_from_dict.py +++ b/tests/test_model_methods/test_save_related_from_dict.py @@ -1,33 +1,24 @@ from typing import List -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class CringeLevel(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="levels", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="levels") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class NickName(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -36,22 +27,14 @@ class NickName(ormar.Model): class NicksHq(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks_x_hq", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks_x_hq") id: int = ormar.Integer(primary_key=True) new_field: str = ormar.String(max_length=200, nullable=True) class HQ(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="hqs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="hqs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -59,11 +42,7 @@ class HQ(ormar.Model): class Company(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="companies", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -71,19 +50,13 @@ class Company(ormar.Model): hq: HQ = ormar.ForeignKey(HQ, related_name="companies") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_saving_related_reverse_fk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): payload = {"companies": [{"name": "Banzai"}], "name": "Main"} hq = HQ(**payload) count = await hq.save_related(follow=True, save_all=True) @@ -99,8 +72,8 @@ async def test_saving_related_reverse_fk(): @pytest.mark.asyncio async def test_saving_related_reverse_fk_multiple(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): payload = { "companies": [{"name": "Banzai"}, {"name": "Yamate"}], "name": "Main", @@ -121,8 +94,8 @@ async def test_saving_related_reverse_fk_multiple(): @pytest.mark.asyncio async def test_saving_related_fk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): payload = {"hq": {"name": "Main"}, "name": "Banzai"} comp = Company(**payload) count = await comp.save_related(follow=True, save_all=True) @@ -137,8 +110,8 @@ async def test_saving_related_fk(): @pytest.mark.asyncio async def test_saving_many_to_many_wo_through(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): payload = { "name": "Main", "nicks": [ @@ -160,9 +133,9 @@ async def test_saving_many_to_many_wo_through(): @pytest.mark.asyncio async def test_saving_many_to_many_with_through(): - async with database: - async with database.transaction(force_rollback=True): - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): + async with base_ormar_config.database.transaction(force_rollback=True): payload = { "name": "Main", "nicks": [ @@ -194,8 +167,8 @@ async def test_saving_many_to_many_with_through(): @pytest.mark.asyncio async def test_saving_nested_with_m2m_and_rev_fk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): payload = { "name": "Main", "nicks": [ @@ -219,8 +192,8 @@ async def test_saving_nested_with_m2m_and_rev_fk(): @pytest.mark.asyncio async def test_saving_nested_with_m2m_and_rev_fk_and_through(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): payload = { "hq": { "name": "Yoko", diff --git a/tests/test_model_methods/test_save_related_uuid.py b/tests/test_model_methods/test_save_related_uuid.py index db7f10180..2139cb573 100644 --- a/tests/test_model_methods/test_save_related_uuid.py +++ b/tests/test_model_methods/test_save_related_uuid.py @@ -6,27 +6,22 @@ import pytest import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Department(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) department_name: str = ormar.String(max_length=100) class Course(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) course_name: str = ormar.String(max_length=100) @@ -35,28 +30,19 @@ class Course(ormar.Model): class Student(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4) name: str = ormar.String(max_length=100) courses = ormar.ManyToMany(Course) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_uuid_pk_in_save_related(): - async with database: + async with base_ormar_config.database: to_save = { "department_name": "Ormar", "courses": [ diff --git a/tests/test_model_methods/test_update.py b/tests/test_model_methods/test_update.py index 22a81c677..fbf11b823 100644 --- a/tests/test_model_methods/test_update.py +++ b/tests/test_model_methods/test_update.py @@ -5,18 +5,15 @@ import pytest import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Director(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="directors", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="directors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="first_name") @@ -24,11 +21,7 @@ class Director(ormar.Model): class Movie(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="movies", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="movies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="title") @@ -37,18 +30,12 @@ class Movie(ormar.Model): director: Optional[Director] = ormar.ForeignKey(Director) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_updating_selected_columns(): - async with database: + async with base_ormar_config.database: director1 = await Director(name="Peter", last_name="Jackson").save() director2 = await Director(name="James", last_name="Cameron").save() @@ -84,7 +71,7 @@ async def test_updating_selected_columns(): @pytest.mark.asyncio async def test_not_passing_columns_or_empty_list_saves_all(): - async with database: + async with base_ormar_config.database: director = await Director(name="James", last_name="Cameron").save() terminator = await Movie( name="Terminator", year=1984, director=director, profit=0.078 diff --git a/tests/test_model_methods/test_upsert.py b/tests/test_model_methods/test_upsert.py index ad216862a..43b241f1d 100644 --- a/tests/test_model_methods/test_upsert.py +++ b/tests/test_model_methods/test_upsert.py @@ -5,18 +5,15 @@ import pytest import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Director(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="directors", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="directors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="first_name") @@ -24,11 +21,7 @@ class Director(ormar.Model): class Movie(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="movies", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="movies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="title") @@ -37,18 +30,12 @@ class Movie(ormar.Model): director: Optional[Director] = ormar.ForeignKey(Director) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_updating_selected_columns(): - async with database: + async with base_ormar_config.database: director1 = await Director(name="Peter", last_name="Jackson").save() await Movie( diff --git a/tests/test_ordering/test_default_model_order.py b/tests/test_ordering/test_default_model_order.py index 90f400649..20bc4a608 100644 --- a/tests/test_ordering/test_default_model_order.py +++ b/tests/test_ordering/test_default_model_order.py @@ -1,21 +1,14 @@ from typing import Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -37,26 +30,20 @@ class Book(ormar.Model): ranking: int = ormar.Integer(nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(autouse=True, scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: await Book.objects.delete(each=True) await Author.objects.delete(each=True) @pytest.mark.asyncio async def test_default_orders_is_applied(): - async with database: + async with base_ormar_config.database: tolkien = await Author(name="J.R.R. Tolkien").save() sapkowski = await Author(name="Andrzej Sapkowski").save() king = await Author(name="Stephen King").save() @@ -77,7 +64,7 @@ async def test_default_orders_is_applied(): @pytest.mark.asyncio async def test_default_orders_is_applied_on_related(): - async with database: + async with base_ormar_config.database: tolkien = await Author(name="J.R.R. Tolkien").save() silmarillion = await Book( author=tolkien, title="The Silmarillion", year=1977 @@ -100,7 +87,7 @@ async def test_default_orders_is_applied_on_related(): @pytest.mark.asyncio async def test_default_orders_is_applied_on_related_two_fields(): - async with database: + async with base_ormar_config.database: sanders = await Author(name="Brandon Sanderson").save() twok = await Book( author=sanders, title="The Way of Kings", year=2010, ranking=10 diff --git a/tests/test_ordering/test_default_relation_order.py b/tests/test_ordering/test_default_relation_order.py index 27e0a628f..6b20cc292 100644 --- a/tests/test_ordering/test_default_relation_order.py +++ b/tests/test_ordering/test_default_relation_order.py @@ -1,22 +1,15 @@ from typing import List, Optional from uuid import UUID, uuid4 -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -59,26 +52,20 @@ class Human(ormar.Model): ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(autouse=True, scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: await Book.objects.delete(each=True) await Author.objects.delete(each=True) @pytest.mark.asyncio async def test_default_orders_is_applied_from_reverse_relation(): - async with database: + async with base_ormar_config.database: tolkien = await Author(name="J.R.R. Tolkien").save() hobbit = await Book(author=tolkien, title="The Hobbit", year=1933).save() silmarillion = await Book( @@ -96,7 +83,7 @@ async def test_default_orders_is_applied_from_reverse_relation(): @pytest.mark.asyncio async def test_default_orders_is_applied_from_relation(): - async with database: + async with base_ormar_config.database: bret = await Author(name="Peter V. Bret").save() tds = await Book( author=bret, title="The Desert Spear", year=2010, ranking=9 @@ -113,7 +100,7 @@ async def test_default_orders_is_applied_from_relation(): @pytest.mark.asyncio async def test_default_orders_is_applied_from_relation_on_m2m(): - async with database: + async with base_ormar_config.database: alice = await Human(name="Alice").save() spot = await Animal(name="Spot", specie="Cat").save() @@ -132,7 +119,7 @@ async def test_default_orders_is_applied_from_relation_on_m2m(): @pytest.mark.asyncio async def test_default_orders_is_applied_from_reverse_relation_on_m2m(): - async with database: + async with base_ormar_config.database: max = await Animal(name="Max", specie="Dog").save() joe = await Human(name="Joe").save() zack = await Human(name="Zack").save() diff --git a/tests/test_ordering/test_default_through_relation_order.py b/tests/test_ordering/test_default_through_relation_order.py index b2a59b07e..1d0e1daa5 100644 --- a/tests/test_ordering/test_default_through_relation_order.py +++ b/tests/test_ordering/test_default_through_relation_order.py @@ -1,10 +1,8 @@ from typing import Any, Dict, List, Tuple, Type, cast from uuid import UUID, uuid4 -import databases import ormar import pytest -import sqlalchemy from ormar import ( Model, ModelDefinitionError, @@ -14,16 +12,11 @@ pre_update, ) -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Animal(ormar.Model): @@ -66,18 +59,12 @@ class Human2(ormar.Model): ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_ordering_by_through_fail(): - async with database: + async with base_ormar_config.database: alice = await Human2(name="Alice").save() spot = await Animal(name="Spot").save() await alice.favoriteAnimals.add(spot) @@ -252,7 +239,7 @@ async def reorder_links_on_remove( @pytest.mark.asyncio async def test_ordering_by_through_on_m2m_field(): - async with database: + async with base_ormar_config.database: def verify_order(instance, expected): field_name = ( diff --git a/tests/test_ordering/test_proper_order_of_sorting_apply.py b/tests/test_ordering/test_proper_order_of_sorting_apply.py index 96dfb1fc7..9f7c117b7 100644 --- a/tests/test_ordering/test_proper_order_of_sorting_apply.py +++ b/tests/test_ordering/test_proper_order_of_sorting_apply.py @@ -1,21 +1,14 @@ from typing import Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -37,26 +30,20 @@ class Book(ormar.Model): ranking: int = ormar.Integer(nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(autouse=True, scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: await Book.objects.delete(each=True) await Author.objects.delete(each=True) @pytest.mark.asyncio async def test_default_orders_is_applied_from_reverse_relation(): - async with database: + async with base_ormar_config.database: tolkien = await Author(name="J.R.R. Tolkien").save() hobbit = await Book(author=tolkien, title="The Hobbit", year=1933).save() silmarillion = await Book( diff --git a/tests/test_queries/test_adding_related.py b/tests/test_queries/test_adding_related.py index c6ce9e2dc..247999241 100644 --- a/tests/test_queries/test_adding_related.py +++ b/tests/test_queries/test_adding_related.py @@ -1,31 +1,24 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Department(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Course(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -33,18 +26,12 @@ class Course(ormar.Model): department: Optional[Department] = ormar.ForeignKey(Department) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_adding_relation_to_reverse_saves_the_child(): - async with database: + async with base_ormar_config.database: department = await Department(name="Science").save() course = Course(name="Math", completed=False) diff --git a/tests/test_queries/test_aggr_functions.py b/tests/test_queries/test_aggr_functions.py index c74b77fbe..c7986d783 100644 --- a/tests/test_queries/test_aggr_functions.py +++ b/tests/test_queries/test_aggr_functions.py @@ -1,22 +1,15 @@ from typing import Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy from ormar.exceptions import QueryDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -38,19 +31,13 @@ class Book(ormar.Model): ranking: int = ormar.Integer(nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(autouse=True, scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: await Book.objects.delete(each=True) await Author.objects.delete(each=True) @@ -64,7 +51,7 @@ async def sample_data(): @pytest.mark.asyncio async def test_min_method(): - async with database: + async with base_ormar_config.database: await sample_data() assert await Book.objects.min("year") == 1920 result = await Book.objects.min(["year", "ranking"]) @@ -88,7 +75,7 @@ async def test_min_method(): @pytest.mark.asyncio async def test_max_method(): - async with database: + async with base_ormar_config.database: await sample_data() assert await Book.objects.max("year") == 1930 result = await Book.objects.max(["year", "ranking"]) @@ -112,7 +99,7 @@ async def test_max_method(): @pytest.mark.asyncio async def test_sum_method(): - async with database: + async with base_ormar_config.database: await sample_data() assert await Book.objects.sum("year") == 5773 result = await Book.objects.sum(["year", "ranking"]) @@ -137,7 +124,7 @@ async def test_sum_method(): @pytest.mark.asyncio async def test_avg_method(): - async with database: + async with base_ormar_config.database: await sample_data() assert round(float(await Book.objects.avg("year")), 2) == 1924.33 result = await Book.objects.avg(["year", "ranking"]) @@ -165,7 +152,7 @@ async def test_avg_method(): @pytest.mark.asyncio async def test_queryset_method(): - async with database: + async with base_ormar_config.database: await sample_data() author = await Author.objects.select_related("books").get() assert await author.books.min("year") == 1920 @@ -179,7 +166,7 @@ async def test_queryset_method(): @pytest.mark.asyncio async def test_count_method(): - async with database: + async with base_ormar_config.database: await sample_data() count = await Author.objects.select_related("books").count() diff --git a/tests/test_queries/test_deep_relations_select_all.py b/tests/test_queries/test_deep_relations_select_all.py index 7f2caf46f..3e7bc84f9 100644 --- a/tests/test_queries/test_deep_relations_select_all.py +++ b/tests/test_queries/test_deep_relations_select_all.py @@ -1,21 +1,16 @@ -import databases import ormar import pytest -import sqlalchemy from sqlalchemy import func -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Chart(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="charts", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="charts") chart_id = ormar.Integer(primary_key=True, autoincrement=True) name = ormar.String(max_length=200, unique=True, index=True) @@ -29,11 +24,7 @@ class Chart(ormar.Model): class Report(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="reports", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="reports") report_id = ormar.Integer(primary_key=True, autoincrement=True) name = ormar.String(max_length=200, unique=True, index=True) @@ -42,11 +33,7 @@ class Report(ormar.Model): class Language(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="languages", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="languages") language_id = ormar.Integer(primary_key=True, autoincrement=True) code = ormar.String(max_length=5) @@ -54,22 +41,14 @@ class Language(ormar.Model): class TranslationNode(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="translation_nodes", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="translation_nodes") node_id = ormar.Integer(primary_key=True, autoincrement=True) node_type = ormar.String(max_length=200) class Translation(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="translations", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="translations") translation_id = ormar.Integer(primary_key=True, autoincrement=True) node_id = ormar.ForeignKey(TranslationNode, related_name="translations") @@ -78,11 +57,7 @@ class Translation(ormar.Model): class Filter(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="filters", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="filters") filter_id = ormar.Integer(primary_key=True, autoincrement=True) name = ormar.String(max_length=200, unique=True, index=True) @@ -96,11 +71,7 @@ class Filter(ormar.Model): class FilterValue(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="filter_values", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="filter_values") value_id = ormar.Integer(primary_key=True, autoincrement=True) value = ormar.String(max_length=300) @@ -110,11 +81,7 @@ class FilterValue(ormar.Model): class FilterXReport(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="filters_x_reports", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="filters_x_reports") filter_x_report_id = ormar.Integer(primary_key=True) filter = ormar.ForeignKey(Filter, name="filter_id", related_name="reports") @@ -125,11 +92,7 @@ class FilterXReport(ormar.Model): class ChartXReport(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="charts_x_reports", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="charts_x_reports") chart_x_report_id = ormar.Integer(primary_key=True) chart = ormar.ForeignKey(Chart, name="chart_id", related_name="reports") @@ -139,11 +102,7 @@ class ChartXReport(ormar.Model): class ChartColumn(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="charts_columns", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="charts_columns") column_id = ormar.Integer(primary_key=True, autoincrement=True) chart = ormar.ForeignKey(Chart, name="chart_id", related_name="columns") @@ -152,17 +111,11 @@ class ChartColumn(ormar.Model): translation = ormar.ForeignKey(TranslationNode, name="translation_node_id") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_saving_related_fk_rel(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await Report.objects.select_all(follow=True).all() diff --git a/tests/test_queries/test_filter_groups.py b/tests/test_queries/test_filter_groups.py index 1eb002b49..c0af4c8bf 100644 --- a/tests/test_queries/test_filter_groups.py +++ b/tests/test_queries/test_filter_groups.py @@ -1,19 +1,12 @@ from typing import Optional -import databases import ormar -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -32,6 +25,9 @@ class Book(ormar.Model): year: int = ormar.Integer(nullable=True) +create_test_database = init_tests(base_ormar_config) + + def test_or_group(): result = ormar.or_(name="aa", books__title="bb") result.resolve(model_cls=Author) diff --git a/tests/test_queries/test_indirect_relations_to_self.py b/tests/test_queries/test_indirect_relations_to_self.py index c9e5094be..ae4a91736 100644 --- a/tests/test_queries/test_indirect_relations_to_self.py +++ b/tests/test_queries/test_indirect_relations_to_self.py @@ -1,22 +1,17 @@ from datetime import datetime -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Node(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="node", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="node") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=120) @@ -25,11 +20,7 @@ class Node(ormar.Model): class Edge(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="edge", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="edge") id: str = ormar.String(primary_key=True, max_length=12) src_node: Node = ormar.ForeignKey(Node, related_name="next_edges") @@ -38,18 +29,12 @@ class Edge(ormar.Model): created_at: datetime = ormar.DateTime(timezone=True, default=datetime.now) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_sort_order_on_main_model(): - async with database: + async with base_ormar_config.database: node1 = await Node(name="Node 1").save() node2 = await Node(name="Node 2").save() node3 = await Node(name="Node 3").save() diff --git a/tests/test_queries/test_isnull_filter.py b/tests/test_queries/test_isnull_filter.py index e3e421459..4f7fc79ff 100644 --- a/tests/test_queries/test_isnull_filter.py +++ b/tests/test_queries/test_isnull_filter.py @@ -1,20 +1,13 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -34,11 +27,7 @@ class Book(ormar.Model): class JsonModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - tablename="jsons", - ) + ormar_config = base_ormar_config.copy(tablename="jsons") id = ormar.Integer(primary_key=True) text_field = ormar.Text(nullable=True) @@ -46,18 +35,12 @@ class JsonModel(ormar.Model): json_not_null = ormar.JSON() -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_is_null(): - async with database: + async with base_ormar_config.database: tolkien = await Author.objects.create(name="J.R.R. Tolkien") await Book.objects.create(author=tolkien, title="The Hobbit") await Book.objects.create( @@ -99,7 +82,7 @@ async def test_is_null(): @pytest.mark.asyncio async def test_isnull_json(): - async with database: + async with base_ormar_config.database: author = await JsonModel.objects.create(json_not_null=None) assert author.json_field is None non_null_text_fields = await JsonModel.objects.all(text_field__isnull=False) diff --git a/tests/test_queries/test_nested_reverse_relations.py b/tests/test_queries/test_nested_reverse_relations.py index 679b53b7c..b55f11bcf 100644 --- a/tests/test_queries/test_nested_reverse_relations.py +++ b/tests/test_queries/test_nested_reverse_relations.py @@ -1,20 +1,14 @@ from typing import Optional -import databases import ormar import pytest import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class DataSource(ormar.Model): @@ -45,18 +39,12 @@ class DataSourceTableColumn(ormar.Model): ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): # pragma: no cover - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_double_nested_reverse_relation(): - async with database: + async with base_ormar_config.database: data_source = await DataSource(name="local").save() test_tables = [ { diff --git a/tests/test_queries/test_non_relation_fields_not_merged.py b/tests/test_queries/test_non_relation_fields_not_merged.py index b64302bd2..97b3c70a7 100644 --- a/tests/test_queries/test_non_relation_fields_not_merged.py +++ b/tests/test_queries/test_non_relation_fields_not_merged.py @@ -1,20 +1,13 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Chart(ormar.Model): @@ -31,18 +24,12 @@ class Config(ormar.Model): chart: Optional[Chart] = ormar.ForeignKey(Chart) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_list_field_that_is_not_relation_is_not_merged(): - async with database: + async with base_ormar_config.database: chart = await Chart.objects.create(datasets=[{"test": "ok"}]) await Config.objects.create(chart=chart) await Config.objects.create(chart=chart) diff --git a/tests/test_queries/test_or_filters.py b/tests/test_queries/test_or_filters.py index 039d3df84..05c2e556e 100644 --- a/tests/test_queries/test_or_filters.py +++ b/tests/test_queries/test_or_filters.py @@ -1,21 +1,14 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy from ormar.exceptions import QueryDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -34,18 +27,12 @@ class Book(ormar.Model): year: int = ormar.Integer(nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_or_filters(): - async with database: + async with base_ormar_config.database: tolkien = await Author(name="J.R.R. Tolkien").save() await Book(author=tolkien, title="The Hobbit", year=1933).save() await Book(author=tolkien, title="The Lord of the Rings", year=1955).save() diff --git a/tests/test_queries/test_order_by.py b/tests/test_queries/test_order_by.py index 187381aa4..6c091805f 100644 --- a/tests/test_queries/test_order_by.py +++ b/tests/test_queries/test_order_by.py @@ -1,22 +1,17 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Song(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="songs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="songs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -24,33 +19,21 @@ class Song(ormar.Model): class Owner(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="owners", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="owners") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class AliasNested(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="aliases_nested", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="aliases_nested") id: int = ormar.Integer(name="alias_id", primary_key=True) name: str = ormar.String(name="alias_name", max_length=100) class AliasTest(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="aliases", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="aliases") id: int = ormar.Integer(name="alias_id", primary_key=True) name: str = ormar.String(name="alias_name", max_length=100) @@ -58,11 +41,7 @@ class AliasTest(ormar.Model): class Toy(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="toys", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="toys") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -70,22 +49,14 @@ class Toy(ormar.Model): class Factory(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="factories", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="factories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Car(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="cars", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="cars") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -93,29 +64,19 @@ class Car(ormar.Model): class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="users", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="users") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) cars: List[Car] = ormar.ManyToMany(Car) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_sort_order_on_main_model(): - async with database: + async with base_ormar_config.database: await Song.objects.create(name="Song 3", sort_order=3) await Song.objects.create(name="Song 1", sort_order=1) await Song.objects.create(name="Song 2", sort_order=2) @@ -174,7 +135,7 @@ async def test_sort_order_on_main_model(): @pytest.mark.asyncio async def test_sort_order_on_related_model(): - async with database: + async with base_ormar_config.database: aphrodite = await Owner.objects.create(name="Aphrodite") hermes = await Owner.objects.create(name="Hermes") zeus = await Owner.objects.create(name="Zeus") @@ -260,7 +221,7 @@ async def test_sort_order_on_related_model(): @pytest.mark.asyncio async def test_sort_order_on_many_to_many(): - async with database: + async with base_ormar_config.database: factory1 = await Factory.objects.create(name="Factory 1") factory2 = await Factory.objects.create(name="Factory 2") @@ -334,7 +295,7 @@ async def test_sort_order_on_many_to_many(): @pytest.mark.asyncio async def test_sort_order_with_aliases(): - async with database: + async with base_ormar_config.database: al1 = await AliasTest.objects.create(name="Test4") al2 = await AliasTest.objects.create(name="Test2") al3 = await AliasTest.objects.create(name="Test1") diff --git a/tests/test_queries/test_pagination.py b/tests/test_queries/test_pagination.py index b36360c1f..5215b9f89 100644 --- a/tests/test_queries/test_pagination.py +++ b/tests/test_queries/test_pagination.py @@ -1,19 +1,12 @@ -import databases import ormar import pytest -import sqlalchemy from ormar.exceptions import QueryDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Car(ormar.Model): @@ -35,19 +28,13 @@ class User(ormar.Model): cars = ormar.ManyToMany(Car, through=UsersCar) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_limit_zero(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): for i in range(5): await Car(name=f"{i}").save() @@ -58,8 +45,8 @@ async def test_limit_zero(): @pytest.mark.asyncio async def test_pagination_errors(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): with pytest.raises(QueryDefinitionError): await Car.objects.paginate(0).all() @@ -69,8 +56,8 @@ async def test_pagination_errors(): @pytest.mark.asyncio async def test_pagination_on_single_model(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): for i in range(20): await Car(name=f"{i}").save() @@ -93,8 +80,8 @@ async def test_pagination_on_single_model(): @pytest.mark.asyncio async def test_proxy_pagination(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): user = await User(name="Jon").save() for i in range(20): diff --git a/tests/test_queries/test_queryproxy_on_m2m_models.py b/tests/test_queries/test_queryproxy_on_m2m_models.py index 4108a52a7..93a09b874 100644 --- a/tests/test_queries/test_queryproxy_on_m2m_models.py +++ b/tests/test_queries/test_queryproxy_on_m2m_models.py @@ -1,34 +1,25 @@ from typing import List, Optional, Union -import databases import ormar import pytest -import sqlalchemy from ormar.exceptions import QueryDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Subject(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="subjects", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="subjects") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=80) class Author(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="authors", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -36,11 +27,7 @@ class Author(ormar.Model): class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) @@ -49,19 +36,11 @@ class Category(ormar.Model): class PostCategory(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="posts_categories", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="posts_categories") class Post(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="posts", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="posts") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -71,18 +50,13 @@ class Post(ormar.Model): author: Optional[Author] = ormar.ForeignKey(Author) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_queryset_methods(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): guido = await Author.objects.create( first_name="Guido", last_name="Van Rossum" ) @@ -187,8 +161,8 @@ async def test_queryset_methods(): @pytest.mark.asyncio async def test_queryset_update(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): guido = await Author.objects.create( first_name="Guido", last_name="Van Rossum" ) diff --git a/tests/test_queries/test_queryset_level_methods.py b/tests/test_queries/test_queryset_level_methods.py index b4509c3e5..93805c28f 100644 --- a/tests/test_queries/test_queryset_level_methods.py +++ b/tests/test_queries/test_queryset_level_methods.py @@ -1,11 +1,9 @@ from enum import Enum from typing import Optional -import databases import ormar import pydantic import pytest -import sqlalchemy from ormar import QuerySet from ormar.exceptions import ( ModelListEmptyError, @@ -14,10 +12,11 @@ ) from pydantic import Json -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config(force_rollback=True) class MySize(Enum): @@ -26,11 +25,7 @@ class MySize(Enum): class Book(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="books", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -43,11 +38,7 @@ class Book(ormar.Model): class ToDo(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="todos", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="todos") id: int = ormar.Integer(primary_key=True) text: str = ormar.String(max_length=500) @@ -57,22 +48,14 @@ class ToDo(ormar.Model): class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=500) class Note(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="notes", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="notes") id: int = ormar.Integer(primary_key=True) text: str = ormar.String(max_length=500) @@ -80,11 +63,7 @@ class Note(ormar.Model): class ItemConfig(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - tablename="item_config", - ) + ormar_config = base_ormar_config.copy(tablename="item_config") id: Optional[int] = ormar.Integer(primary_key=True) item_id: str = ormar.String(max_length=32, index=True) @@ -102,9 +81,7 @@ async def first_or_404(self, *args, **kwargs): class Customer(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, + ormar_config = base_ormar_config.copy( tablename="customer", queryset_class=QuerySetCls, ) @@ -114,29 +91,19 @@ class Customer(ormar.Model): class JsonTestModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - tablename="test_model", - ) + ormar_config = base_ormar_config.copy(tablename="test_model") id: int = ormar.Integer(primary_key=True) json_field: Json = ormar.JSON() -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_delete_and_update(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await Book.objects.create( title="Tom Sawyer", author="Twain, Mark", genre="Adventure" ) @@ -191,7 +158,7 @@ async def test_delete_and_update(): @pytest.mark.asyncio async def test_get_or_create(): - async with database: + async with base_ormar_config.database: tom, created = await Book.objects.get_or_create( title="Volume I", author="Anonymous", genre="Fiction" ) @@ -217,7 +184,7 @@ async def test_get_or_create(): @pytest.mark.asyncio async def test_get_or_create_with_defaults(): - async with database: + async with base_ormar_config.database: book, created = await Book.objects.get_or_create( title="Nice book", _defaults={"author": "Mojix", "genre": "Historic"} ) @@ -253,7 +220,7 @@ async def test_get_or_create_with_defaults(): @pytest.mark.asyncio async def test_update_or_create(): - async with database: + async with base_ormar_config.database: tom = await Book.objects.update_or_create( title="Volume I", author="Anonymous", genre="Fiction" ) @@ -276,7 +243,7 @@ async def test_update_or_create(): @pytest.mark.asyncio async def test_bulk_create(): - async with database: + async with base_ormar_config.database: await ToDo.objects.bulk_create( [ ToDo(text="Buy the groceries."), @@ -299,7 +266,7 @@ async def test_bulk_create(): @pytest.mark.asyncio async def test_bulk_create_json_field(): - async with database: + async with base_ormar_config.database: json_value = {"a": 1} test_model_1 = JsonTestModel(id=1, json_field=json_value) test_model_2 = JsonTestModel(id=2, json_field=json_value) @@ -319,7 +286,7 @@ async def test_bulk_create_json_field(): query = table.select().where(table.c.json_field["a"].as_integer() == 1) res = [ JsonTestModel.from_row(record, source_model=JsonTestModel) - for record in await database.fetch_all(query) + for record in await base_ormar_config.database.fetch_all(query) ] assert test_model_1 in res @@ -329,7 +296,7 @@ async def test_bulk_create_json_field(): @pytest.mark.asyncio async def test_bulk_create_with_relation(): - async with database: + async with base_ormar_config.database: category = await Category.objects.create(name="Sample Category") await Note.objects.bulk_create( @@ -347,7 +314,7 @@ async def test_bulk_create_with_relation(): @pytest.mark.asyncio async def test_bulk_update(): - async with database: + async with base_ormar_config.database: await ToDo.objects.bulk_create( [ ToDo(text="Buy the groceries."), @@ -378,7 +345,7 @@ async def test_bulk_update(): @pytest.mark.asyncio async def test_bulk_update_with_only_selected_columns(): - async with database: + async with base_ormar_config.database: await ToDo.objects.bulk_create( [ ToDo(text="Reset the world simulation.", completed=False), @@ -407,7 +374,7 @@ async def test_bulk_update_with_only_selected_columns(): @pytest.mark.asyncio async def test_bulk_update_with_relation(): - async with database: + async with base_ormar_config.database: category = await Category.objects.create(name="Sample Category") category2 = await Category.objects.create(name="Sample II Category") @@ -436,7 +403,7 @@ async def test_bulk_update_with_relation(): @pytest.mark.asyncio async def test_bulk_update_not_saved_objts(): - async with database: + async with base_ormar_config.database: category = await Category.objects.create(name="Sample Category") with pytest.raises(ModelPersistenceError): await Note.objects.bulk_update( @@ -452,7 +419,7 @@ async def test_bulk_update_not_saved_objts(): @pytest.mark.asyncio async def test_bulk_operations_with_json(): - async with database: + async with base_ormar_config.database: items = [ ItemConfig(item_id="test1"), ItemConfig(item_id="test2"), @@ -480,14 +447,14 @@ async def test_bulk_operations_with_json(): query = table.select().where(table.c.pairs["b"].as_integer() == 2) res = [ ItemConfig.from_row(record, source_model=ItemConfig) - for record in await database.fetch_all(query) + for record in await base_ormar_config.database.fetch_all(query) ] assert len(res) == 2 @pytest.mark.asyncio async def test_custom_queryset_cls(): - async with database: + async with base_ormar_config.database: with pytest.raises(ValueError): await Customer.objects.first_or_404(id=1) @@ -498,7 +465,7 @@ async def test_custom_queryset_cls(): @pytest.mark.asyncio async def test_filter_enum(): - async with database: + async with base_ormar_config.database: it = ItemConfig(item_id="test_1") await it.save() diff --git a/tests/test_queries/test_quoting_table_names_in_on_join_clause.py b/tests/test_queries/test_quoting_table_names_in_on_join_clause.py index 921cbbb90..299246209 100644 --- a/tests/test_queries/test_quoting_table_names_in_on_join_clause.py +++ b/tests/test_queries/test_quoting_table_names_in_on_join_clause.py @@ -2,25 +2,18 @@ import uuid from typing import Dict, Optional, Union -import databases import ormar import pytest -import sqlalchemy -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() -engine = create_engine(DATABASE_URL) + +base_ormar_config = create_config() class Team(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="team", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="team") id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) name = ormar.Text(nullable=True) @@ -30,11 +23,7 @@ class Team(ormar.Model): class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="user", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="user") id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) client_user_id = ormar.Text() @@ -43,24 +32,16 @@ class User(ormar.Model): class Order(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="order", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="order") id: uuid.UUID = ormar.UUID(default=uuid.uuid4, primary_key=True, index=True) user: Optional[Union[User, Dict]] = ormar.ForeignKey(User) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_quoting_on_clause_without_prefix(): - async with database: + async with base_ormar_config.database: await User.objects.select_related("orders").all() diff --git a/tests/test_queries/test_reserved_sql_keywords_escaped.py b/tests/test_queries/test_reserved_sql_keywords_escaped.py index 544d714d3..ad0d3a45c 100644 --- a/tests/test_queries/test_reserved_sql_keywords_escaped.py +++ b/tests/test_queries/test_reserved_sql_keywords_escaped.py @@ -1,18 +1,11 @@ -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config(force_rollback=True) class User(ormar.Model): @@ -39,18 +32,12 @@ class Task(ormar.Model): user = ormar.ForeignKey(User) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_single_model_quotes(): - async with database: + async with base_ormar_config.database: await User.objects.create( user="test", first="first", @@ -66,7 +53,7 @@ async def test_single_model_quotes(): @pytest.mark.asyncio async def test_two_model_quotes(): - async with database: + async with base_ormar_config.database: user = await User.objects.create( user="test", first="first", diff --git a/tests/test_queries/test_reverse_fk_queryset.py b/tests/test_queries/test_reverse_fk_queryset.py index 425653ed6..1a629b21e 100644 --- a/tests/test_queries/test_reverse_fk_queryset.py +++ b/tests/test_queries/test_reverse_fk_queryset.py @@ -1,23 +1,18 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy from ormar import NoMatch -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True, name="album_id") name: str = ormar.String(max_length=100) @@ -25,22 +20,14 @@ class Album(ormar.Model): class Writer(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="writers", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="writers") id: int = ormar.Integer(primary_key=True, name="writer_id") name: str = ormar.String(max_length=100) class Track(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tracks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tracks") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album, name="album_id") @@ -70,19 +57,13 @@ async def get_sample_data(): return album, [track1, track2, tracks3] -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_quering_by_reverse_fk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): sample_data = await get_sample_data() track1 = sample_data[1][0] album = await Album.objects.first() @@ -136,8 +117,8 @@ async def test_quering_by_reverse_fk(): @pytest.mark.asyncio async def test_getting(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): sample_data = await get_sample_data() album = sample_data[0] track1 = await album.tracks.fields(["album", "title", "position"]).get( @@ -206,8 +187,8 @@ async def test_getting(): @pytest.mark.asyncio async def test_cleaning_related(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): sample_data = await get_sample_data() album = sample_data[0] await album.tracks.clear(keep_reversed=False) @@ -221,8 +202,8 @@ async def test_cleaning_related(): @pytest.mark.asyncio async def test_loading_related(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): sample_data = await get_sample_data() album = sample_data[0] tracks = await album.tracks.select_related("written_by").all() @@ -240,8 +221,8 @@ async def test_loading_related(): @pytest.mark.asyncio async def test_adding_removing(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): sample_data = await get_sample_data() album = sample_data[0] track_new = await Track(title="Rainbow", position=5, play_count=300).save() diff --git a/tests/test_queries/test_selecting_subset_of_columns.py b/tests/test_queries/test_selecting_subset_of_columns.py index e839103aa..90dc80550 100644 --- a/tests/test_queries/test_selecting_subset_of_columns.py +++ b/tests/test_queries/test_selecting_subset_of_columns.py @@ -2,25 +2,20 @@ import itertools from typing import List, Optional -import databases import ormar import pydantic import pytest import pytest_asyncio -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class NickNames(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -28,19 +23,11 @@ class NickNames(ormar.Model): class NicksHq(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="nicks_x_hq", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="nicks_x_hq") class HQ(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="hqs", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="hqs") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="hq_name") @@ -48,11 +35,7 @@ class HQ(ormar.Model): class Company(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="companies", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -61,11 +44,7 @@ class Company(ormar.Model): class Car(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="cars", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="cars") id: int = ormar.Integer(primary_key=True) manufacturer: Optional[Company] = ormar.ForeignKey(Company) @@ -76,13 +55,7 @@ class Car(ormar.Model): aircon_type: str = ormar.String(max_length=20, nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.fixture(scope="module") @@ -94,7 +67,7 @@ def event_loop(): @pytest_asyncio.fixture(autouse=True, scope="module") async def sample_data(event_loop, create_test_database): - async with database: + async with base_ormar_config.database: nick1 = await NickNames.objects.create(name="Nippon", is_lame=False) nick2 = await NickNames.objects.create(name="EroCherry", is_lame=True) hq = await HQ.objects.create(name="Japan") @@ -131,8 +104,8 @@ async def sample_data(event_loop, create_test_database): @pytest.mark.asyncio async def test_selecting_subset(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): all_cars = ( await Car.objects.select_related(["manufacturer__hq__nicks"]) .fields( @@ -240,7 +213,7 @@ async def test_selecting_subset(): @pytest.mark.asyncio async def test_selecting_subset_of_through_model(): - async with database: + async with base_ormar_config.database: car = ( await Car.objects.select_related(["manufacturer__hq__nicks"]) .fields( diff --git a/tests/test_queries/test_values_and_values_list.py b/tests/test_queries/test_values_and_values_list.py index 323ef55fa..bb67b38fe 100644 --- a/tests/test_queries/test_values_and_values_list.py +++ b/tests/test_queries/test_values_and_values_list.py @@ -1,23 +1,16 @@ import asyncio from typing import List, Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy from ormar.exceptions import QueryDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class User(ormar.Model): @@ -52,12 +45,7 @@ class Post(ormar.Model): category: Optional[Category] = ormar.ForeignKey(Category) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.fixture(scope="module") @@ -69,7 +57,7 @@ def event_loop(): @pytest_asyncio.fixture(autouse=True, scope="module") async def sample_data(event_loop, create_test_database): - async with database: + async with base_ormar_config.database: creator = await User(name="Anonymous").save() admin = await Role(name="admin").save() editor = await Role(name="editor").save() @@ -83,7 +71,7 @@ async def sample_data(event_loop, create_test_database): @pytest.mark.asyncio async def test_simple_queryset_values(): - async with database: + async with base_ormar_config.database: posts = await Post.objects.values() assert posts == [ {"id": 1, "name": "Ormar strikes again!", "category": 1}, @@ -94,7 +82,7 @@ async def test_simple_queryset_values(): @pytest.mark.asyncio async def test_queryset_values_nested_relation(): - async with database: + async with base_ormar_config.database: posts = await Post.objects.select_related("category__created_by").values() assert posts == [ { @@ -135,7 +123,7 @@ async def test_queryset_values_nested_relation(): @pytest.mark.asyncio async def test_queryset_values_nested_relation_subset_of_fields(): - async with database: + async with base_ormar_config.database: posts = await Post.objects.select_related("category__created_by").values( ["name", "category__name", "category__created_by__name"] ) @@ -160,7 +148,7 @@ async def test_queryset_values_nested_relation_subset_of_fields(): @pytest.mark.asyncio async def test_queryset_simple_values_list(): - async with database: + async with base_ormar_config.database: posts = await Post.objects.values_list() assert posts == [ (1, "Ormar strikes again!", 1), @@ -171,7 +159,7 @@ async def test_queryset_simple_values_list(): @pytest.mark.asyncio async def test_queryset_nested_relation_values_list(): - async with database: + async with base_ormar_config.database: posts = await Post.objects.select_related("category__created_by").values_list() assert posts == [ (1, "Ormar strikes again!", 1, 1, "News", 0, 1, 1, "Anonymous"), @@ -192,7 +180,7 @@ async def test_queryset_nested_relation_values_list(): @pytest.mark.asyncio async def test_queryset_nested_relation_subset_of_fields_values_list(): - async with database: + async with base_ormar_config.database: posts = await Post.objects.select_related("category__created_by").values_list( ["name", "category__name", "category__created_by__name"] ) @@ -205,7 +193,7 @@ async def test_queryset_nested_relation_subset_of_fields_values_list(): @pytest.mark.asyncio async def test_m2m_values(): - async with database: + async with base_ormar_config.database: user = await User.objects.select_related("roles").values() assert user == [ { @@ -231,7 +219,7 @@ async def test_m2m_values(): @pytest.mark.asyncio async def test_nested_m2m_values(): - async with database: + async with base_ormar_config.database: user = ( await Role.objects.select_related("users__categories") .filter(name="admin") @@ -256,7 +244,7 @@ async def test_nested_m2m_values(): @pytest.mark.asyncio async def test_nested_m2m_values_without_through_explicit(): - async with database: + async with base_ormar_config.database: user = ( await Role.objects.select_related("users__categories") .filter(name="admin") @@ -275,7 +263,7 @@ async def test_nested_m2m_values_without_through_explicit(): @pytest.mark.asyncio async def test_nested_m2m_values_without_through_param(): - async with database: + async with base_ormar_config.database: user = ( await Role.objects.select_related("users__categories") .filter(name="admin") @@ -293,7 +281,7 @@ async def test_nested_m2m_values_without_through_param(): @pytest.mark.asyncio async def test_nested_m2m_values_no_through_and_m2m_models_but_keep_end_model(): - async with database: + async with base_ormar_config.database: user = ( await Role.objects.select_related("users__categories") .filter(name="admin") @@ -306,7 +294,7 @@ async def test_nested_m2m_values_no_through_and_m2m_models_but_keep_end_model(): @pytest.mark.asyncio async def test_nested_flatten_and_exception(): - async with database: + async with base_ormar_config.database: with pytest.raises(QueryDefinitionError): (await Role.objects.fields({"name", "id"}).values_list(flatten=True)) @@ -316,7 +304,7 @@ async def test_nested_flatten_and_exception(): @pytest.mark.asyncio async def test_empty_result(): - async with database: + async with base_ormar_config.database: roles = await Role.objects.filter(Role.name == "test").values_list() roles2 = await Role.objects.filter(Role.name == "test").values() assert roles == roles2 == [] @@ -324,7 +312,7 @@ async def test_empty_result(): @pytest.mark.asyncio async def test_queryset_values_multiple_select_related(): - async with database: + async with base_ormar_config.database: posts = ( await Category.objects.select_related(["created_by__roles", "posts"]) .filter(Category.created_by.roles.name == "editor") @@ -357,7 +345,7 @@ async def test_queryset_values_multiple_select_related(): @pytest.mark.asyncio async def test_querysetproxy_values(): - async with database: + async with base_ormar_config.database: role = ( await Role.objects.select_related("users__categories") .filter(name="admin") @@ -403,7 +391,7 @@ async def test_querysetproxy_values(): @pytest.mark.asyncio async def test_querysetproxy_values_list(): - async with database: + async with base_ormar_config.database: role = ( await Role.objects.select_related("users__categories") .filter(name="admin") diff --git a/tests/test_relations/test_cascades.py b/tests/test_relations/test_cascades.py index 931f7625c..a85e2a70b 100644 --- a/tests/test_relations/test_cascades.py +++ b/tests/test_relations/test_cascades.py @@ -1,44 +1,31 @@ from typing import Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Band(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="bands", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="bands") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class ArtistsBands(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="artists_x_bands", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="artists_x_bands") id: int = ormar.Integer(primary_key=True) class Artist(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="artists", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="artists") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -46,11 +33,7 @@ class Artist(ormar.Model): class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -58,37 +41,27 @@ class Album(ormar.Model): class Track(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tracks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tracks") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album, ondelete="CASCADE") title: str = ormar.String(max_length=100) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: await Band.objects.delete(each=True) await Artist.objects.delete(each=True) @pytest.mark.asyncio async def test_simple_cascade(cleanup): - async with database: + async with base_ormar_config.database: artist = await Artist(name="Dr Alban").save() await Album(name="Jamaica", artist=artist).save() await Artist.objects.delete(id=artist.id) @@ -101,7 +74,7 @@ async def test_simple_cascade(cleanup): @pytest.mark.asyncio async def test_nested_cascade(cleanup): - async with database: + async with base_ormar_config.database: artist = await Artist(name="Dr Alban").save() album = await Album(name="Jamaica", artist=artist).save() await Track(title="Yuhu", album=album).save() @@ -120,7 +93,7 @@ async def test_nested_cascade(cleanup): @pytest.mark.asyncio async def test_many_to_many_cascade(cleanup): - async with database: + async with base_ormar_config.database: artist = await Artist(name="Dr Alban").save() band = await Band(name="Scorpions").save() await artist.bands.add(band) @@ -142,7 +115,7 @@ async def test_many_to_many_cascade(cleanup): @pytest.mark.asyncio async def test_reverse_many_to_many_cascade(cleanup): - async with database: + async with base_ormar_config.database: artist = await Artist(name="Dr Alban").save() band = await Band(name="Scorpions").save() await artist.bands.add(band) diff --git a/tests/test_relations/test_customizing_through_model_relation_names.py b/tests/test_relations/test_customizing_through_model_relation_names.py index 76c0088c0..8a8f22204 100644 --- a/tests/test_relations/test_customizing_through_model_relation_names.py +++ b/tests/test_relations/test_customizing_through_model_relation_names.py @@ -1,29 +1,22 @@ -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) + +base_ormar_config = create_config() class Course(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) course_name: str = ormar.String(max_length=100) class Student(ormar.Model): - ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -34,13 +27,7 @@ class Student(ormar.Model): ) -# create db and tables -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_tables_columns(): @@ -53,8 +40,8 @@ def test_tables_columns(): @pytest.mark.asyncio async def test_working_with_changed_through_names(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): to_save = { "course_name": "basic1", "students": [{"name": "Jack"}, {"name": "Abi"}], diff --git a/tests/test_relations/test_database_fk_creation.py b/tests/test_relations/test_database_fk_creation.py index 58efffbbc..9566dcde5 100644 --- a/tests/test_relations/test_database_fk_creation.py +++ b/tests/test_relations/test_database_fk_creation.py @@ -1,35 +1,26 @@ from typing import Optional -import databases import ormar import pytest import sqlalchemy from ormar.fields.foreign_key import validate_referential_action -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() -engine = sqlalchemy.create_engine(DATABASE_URL) + +base_ormar_config = create_config() class Artist(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="artists", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="artists") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -37,20 +28,14 @@ class Album(ormar.Model): class A(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=64, nullalbe=False) class B(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=64, nullalbe=False) @@ -58,26 +43,18 @@ class B(ormar.Model): class C(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=64, nullalbe=False) b: B = ormar.ForeignKey(to=B, ondelete=ormar.ReferentialAction.CASCADE) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_simple_cascade(): - inspector = sqlalchemy.inspect(engine) + inspector = sqlalchemy.inspect(base_ormar_config.engine) columns = inspector.get_columns("albums") assert len(columns) == 3 col_names = [col.get("name") for col in columns] @@ -103,8 +80,8 @@ def test_validations_referential_action(): @pytest.mark.asyncio async def test_cascade_clear(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): a = await A.objects.create(name="a") b = await B.objects.create(name="b", a=a) await C.objects.create(name="c", b=b) diff --git a/tests/test_relations/test_foreign_keys.py b/tests/test_relations/test_foreign_keys.py index 1899aa00f..f3561c123 100644 --- a/tests/test_relations/test_foreign_keys.py +++ b/tests/test_relations/test_foreign_keys.py @@ -1,23 +1,18 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy from ormar.exceptions import MultipleMatches, NoMatch, RelationshipInstanceError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -25,11 +20,7 @@ class Album(ormar.Model): class Track(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tracks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tracks") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -40,11 +31,7 @@ class Track(ormar.Model): class Cover(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="covers", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="covers") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album, related_name="cover_pictures") @@ -52,22 +39,14 @@ class Cover(ormar.Model): class Organisation(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="org", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="org") id: int = ormar.Integer(primary_key=True) ident: str = ormar.String(max_length=100, choices=["ACME Ltd", "Other ltd"]) class Team(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="teams", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="teams") id: int = ormar.Integer(primary_key=True) org: Optional[Organisation] = ormar.ForeignKey(Organisation) @@ -75,44 +54,34 @@ class Team(ormar.Model): class Member(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="members", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="members") id: int = ormar.Integer(primary_key=True) team: Optional[Team] = ormar.ForeignKey(Team) email: str = ormar.String(max_length=100) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_wrong_query_foreign_key_type(): - async with database: + async with base_ormar_config.database: with pytest.raises(RelationshipInstanceError): Track(title="The Error", album="wrong_pk_type") @pytest.mark.asyncio async def test_setting_explicitly_empty_relation(): - async with database: + async with base_ormar_config.database: track = Track(album=None, title="The Bird", position=1) assert track.album is None @pytest.mark.asyncio async def test_related_name(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): album = await Album.objects.create(name="Vanilla") await Cover.objects.create(album=album, title="The cover file") assert len(album.cover_pictures) == 1 @@ -120,8 +89,8 @@ async def test_related_name(): @pytest.mark.asyncio async def test_model_crud(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): album = Album(name="Jamaica") await album.save() track1 = Track(album=album, title="The Bird", position=1) @@ -152,8 +121,8 @@ async def test_model_crud(): @pytest.mark.asyncio async def test_select_related(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): album = Album(name="Malibu") await album.save() track1 = Track(album=album, title="The Bird", position=1) @@ -181,8 +150,8 @@ async def test_select_related(): @pytest.mark.asyncio async def test_model_removal_from_relations(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): album = Album(name="Chichi") await album.save() track1 = Track(album=album, title="The Birdman", position=1) @@ -223,8 +192,8 @@ async def test_model_removal_from_relations(): @pytest.mark.asyncio async def test_fk_filter(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): malibu = Album(name="Malibu%") await malibu.save() await Track.objects.create(album=malibu, title="The Bird", position=1) @@ -283,8 +252,8 @@ async def test_fk_filter(): @pytest.mark.asyncio async def test_multiple_fk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): acme = await Organisation.objects.create(ident="ACME Ltd") red_team = await Team.objects.create(org=acme, name="Red Team") blue_team = await Team.objects.create(org=acme, name="Blue Team") @@ -309,8 +278,8 @@ async def test_multiple_fk(): @pytest.mark.asyncio async def test_pk_filter(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): fantasies = await Album.objects.create(name="Test") track = await Track.objects.create( album=fantasies, title="Test1", position=1 @@ -332,8 +301,8 @@ async def test_pk_filter(): @pytest.mark.asyncio async def test_limit_and_offset(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): fantasies = await Album.objects.create(name="Limitless") await Track.objects.create( id=None, album=fantasies, title="Sample", position=1 @@ -364,8 +333,8 @@ async def test_limit_and_offset(): @pytest.mark.asyncio async def test_get_exceptions(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): fantasies = await Album.objects.create(name="Test") with pytest.raises(NoMatch): @@ -380,8 +349,8 @@ async def test_get_exceptions(): @pytest.mark.asyncio async def test_wrong_model_passed_as_fk(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): with pytest.raises(RelationshipInstanceError): org = await Organisation.objects.create(ident="ACME Ltd") await Track.objects.create(album=org, title="Test1", position=1) @@ -389,8 +358,8 @@ async def test_wrong_model_passed_as_fk(): @pytest.mark.asyncio async def test_bulk_update_model_with_no_children(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): album = await Album.objects.create(name="Test") album.name = "Test2" await Album.objects.bulk_update([album], columns=["name"]) @@ -401,8 +370,8 @@ async def test_bulk_update_model_with_no_children(): @pytest.mark.asyncio async def test_bulk_update_model_with_children(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): best_seller = await Album.objects.create(name="to_be_best_seller") best_seller2 = await Album.objects.create(name="to_be_best_seller2") not_best_seller = await Album.objects.create(name="unpopular") diff --git a/tests/test_relations/test_m2m_through_fields.py b/tests/test_relations/test_m2m_through_fields.py index 4f1eb849c..99eacf0dd 100644 --- a/tests/test_relations/test_m2m_through_fields.py +++ b/tests/test_relations/test_m2m_through_fields.py @@ -1,20 +1,13 @@ from typing import Any, ForwardRef -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config(force_rollback=True) class Category(ormar.Model): @@ -48,13 +41,7 @@ class Post(ormar.Model): blog = ormar.ForeignKey(Blog) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) class PostCategory2(ormar.Model): @@ -74,7 +61,7 @@ class Post2(ormar.Model): @pytest.mark.asyncio async def test_forward_ref_is_updated(): - async with database: + async with base_ormar_config.database: assert Post2.ormar_config.requires_ref_update Post2.update_forward_refs() @@ -83,7 +70,7 @@ async def test_forward_ref_is_updated(): @pytest.mark.asyncio async def test_setting_fields_on_through_model(): - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() category = await Category(name="Test category").save() await post.categories.add(category) @@ -94,7 +81,7 @@ async def test_setting_fields_on_through_model(): @pytest.mark.asyncio async def test_setting_additional_fields_on_through_model_in_add(): - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() category = await Category(name="Test category").save() await post.categories.add(category, sort_order=1) @@ -104,7 +91,7 @@ async def test_setting_additional_fields_on_through_model_in_add(): @pytest.mark.asyncio async def test_setting_additional_fields_on_through_model_in_create(): - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category2", postcategory={"sort_order": 2} @@ -115,7 +102,7 @@ async def test_setting_additional_fields_on_through_model_in_create(): @pytest.mark.asyncio async def test_getting_additional_fields_from_queryset() -> Any: - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category1", postcategory={"sort_order": 1} @@ -137,7 +124,7 @@ async def test_getting_additional_fields_from_queryset() -> Any: @pytest.mark.asyncio async def test_only_one_side_has_through() -> Any: - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category1", postcategory={"sort_order": 1} @@ -162,7 +149,7 @@ async def test_only_one_side_has_through() -> Any: @pytest.mark.asyncio async def test_filtering_by_through_model() -> Any: - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category1", @@ -189,7 +176,7 @@ async def test_filtering_by_through_model() -> Any: @pytest.mark.asyncio async def test_deep_filtering_by_through_model() -> Any: - async with database: + async with base_ormar_config.database: blog = await Blog(title="My Blog").save() post = await Post(title="Test post", blog=blog).save() @@ -220,7 +207,7 @@ async def test_deep_filtering_by_through_model() -> Any: @pytest.mark.asyncio async def test_ordering_by_through_model() -> Any: - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category1", @@ -255,7 +242,7 @@ async def test_ordering_by_through_model() -> Any: @pytest.mark.asyncio async def test_update_through_models_from_queryset_on_through() -> Any: - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category1", @@ -284,7 +271,7 @@ async def test_update_through_models_from_queryset_on_through() -> Any: @pytest.mark.asyncio async def test_update_through_model_after_load() -> Any: - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category1", @@ -303,7 +290,7 @@ async def test_update_through_model_after_load() -> Any: @pytest.mark.asyncio async def test_update_through_from_related() -> Any: - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category1", @@ -332,7 +319,7 @@ async def test_update_through_from_related() -> Any: @pytest.mark.asyncio async def test_excluding_fields_on_through_model() -> Any: - async with database: + async with base_ormar_config.database: post = await Post(title="Test post").save() await post.categories.create( name="Test category1", diff --git a/tests/test_relations/test_many_to_many.py b/tests/test_relations/test_many_to_many.py index 044724a16..ad1a6fb40 100644 --- a/tests/test_relations/test_many_to_many.py +++ b/tests/test_relations/test_many_to_many.py @@ -1,25 +1,20 @@ import asyncio from typing import List, Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy from ormar.exceptions import ModelPersistenceError, NoMatch, RelationshipInstanceError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config(force_rollback=True) class Author(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="authors", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -27,22 +22,14 @@ class Author(ormar.Model): class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="posts", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="posts") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -57,18 +44,13 @@ def event_loop(): loop.close() -@pytest_asyncio.fixture(autouse=True, scope="module") -async def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: PostCategory = Post.ormar_config.model_fields["categories"].through await PostCategory.objects.delete(each=True) await Post.objects.delete(each=True) @@ -78,7 +60,7 @@ async def cleanup(): @pytest.mark.asyncio async def test_not_saved_raises_error(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author(first_name="Guido", last_name="Van Rossum").save() post = await Post.objects.create(title="Hello, M2M", author=guido) news = Category(name="News") @@ -89,7 +71,7 @@ async def test_not_saved_raises_error(cleanup): @pytest.mark.asyncio async def test_not_existing_raises_error(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author(first_name="Guido", last_name="Van Rossum").save() post = await Post.objects.create(title="Hello, M2M", author=guido) @@ -101,7 +83,7 @@ async def test_not_existing_raises_error(cleanup): @pytest.mark.asyncio async def test_assigning_related_objects(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = await Category.objects.create(name="News") @@ -124,7 +106,7 @@ async def test_assigning_related_objects(cleanup): @pytest.mark.asyncio async def test_quering_of_the_m2m_models(cleanup): - async with database: + async with base_ormar_config.database: # orm can do this already. guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) @@ -159,7 +141,7 @@ async def test_quering_of_the_m2m_models(cleanup): @pytest.mark.asyncio async def test_removal_of_the_relations(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = await Category.objects.create(name="News") @@ -186,7 +168,7 @@ async def test_removal_of_the_relations(cleanup): @pytest.mark.asyncio async def test_selecting_related(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = await Category.objects.create(name="News") @@ -213,7 +195,7 @@ async def test_selecting_related(cleanup): @pytest.mark.asyncio async def test_selecting_related_fail_without_saving(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = Post(title="Hello, M2M", author=guido) with pytest.raises(RelationshipInstanceError): @@ -222,7 +204,7 @@ async def test_selecting_related_fail_without_saving(cleanup): @pytest.mark.asyncio async def test_adding_unsaved_related(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = Category(name="News") @@ -236,7 +218,7 @@ async def test_adding_unsaved_related(cleanup): @pytest.mark.asyncio async def test_removing_unsaved_related(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = Category(name="News") diff --git a/tests/test_relations/test_postgress_select_related_with_limit.py b/tests/test_relations/test_postgress_select_related_with_limit.py index e432255b7..93b4e0914 100644 --- a/tests/test_relations/test_postgress_select_related_with_limit.py +++ b/tests/test_relations/test_postgress_select_related_with_limit.py @@ -4,16 +4,14 @@ from enum import Enum from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config(force_rollback=True) class PrimaryKeyMixin: @@ -25,12 +23,6 @@ class Level(Enum): STAFF = "1" -base_ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, -) - - class User(PrimaryKeyMixin, ormar.Model): """User Model Class to Implement Method for Operations of User Entity""" @@ -65,17 +57,12 @@ class Task(PrimaryKeyMixin, ormar.Model): ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_selecting_related_with_limit(): - async with database: + async with base_ormar_config.database: user1 = await User(mobile="9928917653", password="pass1").save() user2 = await User(mobile="9928917654", password="pass2").save() await Task(name="one", user=user1).save() diff --git a/tests/test_relations/test_prefetch_related.py b/tests/test_relations/test_prefetch_related.py index ab054d50e..5a2dc245a 100644 --- a/tests/test_relations/test_prefetch_related.py +++ b/tests/test_relations/test_prefetch_related.py @@ -1,33 +1,24 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config(force_rollback=True) class RandomSet(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="randoms", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="randoms") id: int = ormar.Integer(name="random_id", primary_key=True) name: str = ormar.String(max_length=100) class Tonation(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tonations", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tonations") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(name="tonation_name", max_length=100) @@ -35,22 +26,14 @@ class Tonation(ormar.Model): class Division(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="divisions", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="divisions") id: int = ormar.Integer(name="division_id", primary_key=True) name: str = ormar.String(max_length=100, nullable=True) class Shop(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="shops", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="shops") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=True) @@ -58,19 +41,11 @@ class Shop(ormar.Model): class AlbumShops(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums_x_shops", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums_x_shops") class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=True) @@ -78,11 +53,7 @@ class Album(ormar.Model): class Track(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tracks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tracks") id: int = ormar.Integer(name="track_id", primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -92,11 +63,7 @@ class Track(ormar.Model): class Cover(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="covers", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="covers") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey( @@ -106,19 +73,13 @@ class Cover(ormar.Model): artist: str = ormar.String(max_length=200, nullable=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_prefetch_related(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): album = Album(name="Malibu") await album.save() ton1 = await Tonation.objects.create(name="B-mol") @@ -196,8 +157,8 @@ async def test_prefetch_related(): @pytest.mark.asyncio async def test_prefetch_related_with_many_to_many(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): div = await Division.objects.create(name="Div 1") shop1 = await Shop.objects.create(name="Shop 1", division=div) shop2 = await Shop.objects.create(name="Shop 2", division=div) @@ -245,8 +206,8 @@ async def test_prefetch_related_with_many_to_many(): @pytest.mark.asyncio async def test_prefetch_related_empty(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await Track.objects.create(title="The Bird", position=1) track = await Track.objects.prefetch_related(["album__cover_pictures"]).get( title="The Bird" @@ -257,8 +218,8 @@ async def test_prefetch_related_empty(): @pytest.mark.asyncio async def test_prefetch_related_with_select_related(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): div = await Division.objects.create(name="Div 1") shop1 = await Shop.objects.create(name="Shop 1", division=div) shop2 = await Shop.objects.create(name="Shop 2", division=div) @@ -330,8 +291,8 @@ async def test_prefetch_related_with_select_related(): @pytest.mark.asyncio async def test_prefetch_related_with_select_related_and_fields(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): div = await Division.objects.create(name="Div 1") shop1 = await Shop.objects.create(name="Shop 1", division=div) shop2 = await Shop.objects.create(name="Shop 2", division=div) diff --git a/tests/test_relations/test_prefetch_related_multiple_models_relation.py b/tests/test_relations/test_prefetch_related_multiple_models_relation.py index bd077a3fb..ecaf722fc 100644 --- a/tests/test_relations/test_prefetch_related_multiple_models_relation.py +++ b/tests/test_relations/test_prefetch_related_multiple_models_relation.py @@ -1,44 +1,30 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -db = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="test_users", - ) + ormar_config = base_ormar_config.copy(tablename="test_users") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) class Signup(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="test_signup", - ) + ormar_config = base_ormar_config.copy(tablename="test_signup") id: int = ormar.Integer(primary_key=True) class Session(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="test_sessions", - ) + ormar_config = base_ormar_config.copy(tablename="test_sessions") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) @@ -52,17 +38,12 @@ class Session(ormar.Model): ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_add_students(): - async with db: + async with base_ormar_config.database: for user_id in [1, 2, 3, 4, 5]: await User.objects.create(name=f"User {user_id}") diff --git a/tests/test_relations/test_python_style_relations.py b/tests/test_relations/test_python_style_relations.py index 422b9ec26..d9287ff4b 100644 --- a/tests/test_relations/test_python_style_relations.py +++ b/tests/test_relations/test_python_style_relations.py @@ -1,23 +1,18 @@ from typing import List, Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Author(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="authors", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -25,22 +20,14 @@ class Author(ormar.Model): class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="posts", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="posts") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -48,18 +35,13 @@ class Post(ormar.Model): author: Optional[Author] = ormar.ForeignKey(Author, related_name="author_posts") -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: PostCategory = Post.ormar_config.model_fields["categories"].through await PostCategory.objects.delete(each=True) await Post.objects.delete(each=True) @@ -69,7 +51,7 @@ async def cleanup(): @pytest.mark.asyncio async def test_selecting_related(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = await Category.objects.create(name="News") diff --git a/tests/test_relations/test_relations_default_exception.py b/tests/test_relations/test_relations_default_exception.py index d88d899b4..2066caf33 100644 --- a/tests/test_relations/test_relations_default_exception.py +++ b/tests/test_relations/test_relations_default_exception.py @@ -1,24 +1,19 @@ # type: ignore from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy from ormar.exceptions import ModelDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Author(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="authors", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -26,25 +21,20 @@ class Author(ormar.Model): class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) +create_test_database = init_tests(base_ormar_config) + + def test_fk_error(): with pytest.raises(ModelDefinitionError): class Post(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="posts", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="posts") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -56,11 +46,7 @@ def test_m2m_error(): with pytest.raises(ModelDefinitionError): class Post(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="posts", - database=database, - metadata=metadata, - ) + ormar_config = base_ormar_config.copy(tablename="posts") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) diff --git a/tests/test_relations/test_replacing_models_with_copy.py b/tests/test_relations/test_replacing_models_with_copy.py index 240caa0b5..436a7006b 100644 --- a/tests/test_relations/test_replacing_models_with_copy.py +++ b/tests/test_relations/test_replacing_models_with_copy.py @@ -1,22 +1,17 @@ from typing import Any, Optional, Tuple, Union -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -26,11 +21,7 @@ class Album(ormar.Model): class Track(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="tracks", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="tracks") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -41,13 +32,7 @@ class Track(ormar.Model): properties: Tuple[str, Any] -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio diff --git a/tests/test_relations/test_saving_related.py b/tests/test_relations/test_saving_related.py index 31e9d5d52..2c777a457 100644 --- a/tests/test_relations/test_saving_related.py +++ b/tests/test_relations/test_saving_related.py @@ -1,24 +1,18 @@ from typing import Union -import databases import ormar import pytest -import sqlalchemy as sa from ormar.exceptions import ModelPersistenceError -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -metadata = sa.MetaData() -db = databases.Database(DATABASE_URL) + +base_ormar_config = create_config() class Category(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="categories", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -26,11 +20,7 @@ class Category(ormar.Model): class Workshop(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="workshops", - metadata=metadata, - database=db, - ) + ormar_config = base_ormar_config.copy(tablename="workshops") id: int = ormar.Integer(primary_key=True) topic: str = ormar.String(max_length=255, index=True) @@ -39,18 +29,13 @@ class Workshop(ormar.Model): ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_model_relationship(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): cat = await Category(name="Foo", code=123).save() ws = await Workshop(topic="Topic 1", category=cat).save() @@ -68,8 +53,8 @@ async def test_model_relationship(): @pytest.mark.asyncio async def test_model_relationship_with_not_saved(): - async with db: - async with db.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): cat = Category(name="Foo", code=123) with pytest.raises(ModelPersistenceError): await Workshop(topic="Topic 1", category=cat).save() diff --git a/tests/test_relations/test_select_related_with_limit.py b/tests/test_relations/test_select_related_with_limit.py index 36d3785ce..1be283a26 100644 --- a/tests/test_relations/test_select_related_with_limit.py +++ b/tests/test_relations/test_select_related_with_limit.py @@ -1,44 +1,30 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -db = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class Keyword(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="keywords", - ) + ormar_config = base_ormar_config.copy(tablename="keywords") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) class KeywordPrimaryModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="primary_models_keywords", - ) + ormar_config = base_ormar_config.copy(tablename="primary_models_keywords") id: int = ormar.Integer(primary_key=True) class PrimaryModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="primary_models", - ) + ormar_config = base_ormar_config.copy(tablename="primary_models") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) @@ -50,11 +36,7 @@ class PrimaryModel(ormar.Model): class SecondaryModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=db, - tablename="secondary_models", - ) + ormar_config = base_ormar_config.copy(tablename="secondary_models") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -65,7 +47,7 @@ class SecondaryModel(ormar.Model): @pytest.mark.asyncio async def test_create_primary_models(): - async with db: + async with base_ormar_config.database: for name, some_text, some_other_text in [ ("Primary 1", "Some text 1", "Some other text 1"), ("Primary 2", "Some text 2", "Some other text 2"), @@ -153,9 +135,4 @@ async def test_create_primary_models(): assert len(models5[2].keywords) == 0 -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) diff --git a/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py b/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py index a79d79485..0f9beebbc 100644 --- a/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py +++ b/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py @@ -2,23 +2,16 @@ from datetime import date from typing import List, Optional, Union -import databases import ormar import pytest import sqlalchemy from ormar import ModelDefinitionError -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Role(ormar.Model): @@ -53,12 +46,7 @@ class User(ormar.Model): lastupdate: date = ormar.DateTime(server_default=sqlalchemy.func.now()) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) def test_wrong_model(): @@ -74,7 +62,7 @@ class User(ormar.Model): @pytest.mark.asyncio async def test_create_primary_models(): - async with database: + async with base_ormar_config.database: await Role.objects.create( name="user", order=0, description="no administration right" ) diff --git a/tests/test_relations/test_selecting_proper_table_prefix.py b/tests/test_relations/test_selecting_proper_table_prefix.py index da5393241..b0de7e05a 100644 --- a/tests/test_relations/test_selecting_proper_table_prefix.py +++ b/tests/test_relations/test_selecting_proper_table_prefix.py @@ -1,44 +1,30 @@ from typing import List, Optional -import databases import ormar import pytest -import sqlalchemy -from sqlalchemy import create_engine -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class User(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - tablename="test_users", - ) + ormar_config = base_ormar_config.copy(tablename="test_users") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) class Signup(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - tablename="test_signup", - ) + ormar_config = base_ormar_config.copy(tablename="test_signup") id: int = ormar.Integer(primary_key=True) class Session(ormar.Model): - ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, - tablename="test_sessions", - ) + ormar_config = base_ormar_config.copy(tablename="test_sessions") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255, index=True) @@ -47,17 +33,12 @@ class Session(ormar.Model): students: Optional[List[User]] = ormar.ManyToMany(User, through=Signup) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest.mark.asyncio async def test_list_sessions_for_user(): - async with database: + async with base_ormar_config.database: for user_id in [1, 2, 3, 4, 5]: await User.objects.create(name=f"User {user_id}") diff --git a/tests/test_relations/test_skipping_reverse.py b/tests/test_relations/test_skipping_reverse.py index b4d2f38e7..3cc49df8f 100644 --- a/tests/test_relations/test_skipping_reverse.py +++ b/tests/test_relations/test_skipping_reverse.py @@ -1,21 +1,14 @@ from typing import List, Optional -import databases import ormar import pytest import pytest_asyncio -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - -base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, -) +base_ormar_config = create_config() class Author(ormar.Model): @@ -42,18 +35,13 @@ class Post(ormar.Model): author: Optional[Author] = ormar.ForeignKey(Author, skip_reverse=True) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: PostCategory = Post.ormar_config.model_fields["categories"].through await PostCategory.objects.delete(each=True) await Post.objects.delete(each=True) @@ -81,7 +69,7 @@ def test_model_definition(): @pytest.mark.asyncio async def test_assigning_related_objects(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = await Category.objects.create(name="News") @@ -109,7 +97,7 @@ async def test_assigning_related_objects(cleanup): @pytest.mark.asyncio async def test_quering_of_related_model_works_but_no_result(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = await Category.objects.create(name="News") @@ -149,7 +137,7 @@ async def test_quering_of_related_model_works_but_no_result(cleanup): @pytest.mark.asyncio async def test_removal_of_the_relations(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") post = await Post.objects.create(title="Hello, M2M", author=guido) news = await Category.objects.create(name="News") @@ -174,7 +162,7 @@ async def test_removal_of_the_relations(cleanup): @pytest.mark.asyncio async def test_selecting_related(cleanup): - async with database: + async with base_ormar_config.database: guido = await Author.objects.create(first_name="Guido", last_name="Van Rossum") guido2 = await Author.objects.create( first_name="Guido2", last_name="Van Rossum" diff --git a/tests/test_relations/test_through_relations_fail.py b/tests/test_relations/test_through_relations_fail.py index 129fc21b2..5057d907b 100644 --- a/tests/test_relations/test_through_relations_fail.py +++ b/tests/test_relations/test_through_relations_fail.py @@ -1,23 +1,17 @@ # type: ignore -import databases import ormar import pytest -import sqlalchemy from ormar import ModelDefinitionError -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() +base_ormar_config = create_config() -def test_through_with_relation_fails(): - base_ormar_config = ormar.OrmarConfig( - database=database, - metadata=metadata, - ) +def test_through_with_relation_fails(): class Category(ormar.Model): ormar_config = base_ormar_config.copy(tablename="categories") @@ -46,3 +40,6 @@ class Post(ormar.Model): id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) categories = ormar.ManyToMany(Category, through=PostCategory) + + +create_test_database = init_tests(base_ormar_config) diff --git a/tests/test_relations/test_weakref_checking.py b/tests/test_relations/test_weakref_checking.py index b246e0502..3a666bbae 100644 --- a/tests/test_relations/test_weakref_checking.py +++ b/tests/test_relations/test_weakref_checking.py @@ -1,30 +1,21 @@ -import databases import ormar -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.settings import create_config -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() +from tests.lifespan import init_tests class Band(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="bands", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="bands") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Artist(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="artists", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="artists") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -32,6 +23,9 @@ class Artist(ormar.Model): band: Band = ormar.ForeignKey(Band) +create_test_database = init_tests(base_ormar_config) + + def test_weakref_init(): band = Band(name="Band") artist1 = Artist(name="Artist 1", band=band) diff --git a/tests/test_signals/test_signals.py b/tests/test_signals/test_signals.py index 251e91734..5e6405b8c 100644 --- a/tests/test_signals/test_signals.py +++ b/tests/test_signals/test_signals.py @@ -1,11 +1,9 @@ from typing import Optional -import databases import ormar import pydantic import pytest import pytest_asyncio -import sqlalchemy from ormar import ( post_bulk_update, post_delete, @@ -18,18 +16,15 @@ from ormar.exceptions import SignalDefinitionError from ormar.signals import SignalEmitter -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class AuditLog(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="audits", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="audits") id: int = ormar.Integer(primary_key=True) event_type: str = ormar.String(max_length=100) @@ -37,22 +32,14 @@ class AuditLog(ormar.Model): class Cover(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="covers", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="covers") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=100) class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -61,19 +48,13 @@ class Album(ormar.Model): cover: Optional[Cover] = ormar.ForeignKey(Cover) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: await AuditLog.objects.delete(each=True) @@ -98,8 +79,8 @@ def test_invalid_signal(): @pytest.mark.asyncio async def test_signal_functions(cleanup): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): @pre_save(Album) async def before_save(sender, instance, **kwargs): @@ -221,8 +202,8 @@ async def after_bulk_update(sender, instances, **kwargs): @pytest.mark.asyncio async def test_multiple_signals(cleanup): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): @pre_save(Album) async def before_save(sender, instance, **kwargs): @@ -252,8 +233,8 @@ async def before_save2(sender, instance, **kwargs): @pytest.mark.asyncio async def test_static_methods_as_signals(cleanup): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): class AlbumAuditor: event_type = "ALBUM_INSTANCE" @@ -277,8 +258,8 @@ async def before_save(sender, instance, **kwargs): @pytest.mark.asyncio async def test_methods_as_signals(cleanup): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): class AlbumAuditor: def __init__(self): @@ -304,8 +285,8 @@ async def before_save(self, sender, instance, **kwargs): @pytest.mark.asyncio async def test_multiple_senders_signal(cleanup): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): @pre_save([Album, Cover]) async def before_save(sender, instance, **kwargs): @@ -332,8 +313,8 @@ async def before_save(sender, instance, **kwargs): @pytest.mark.asyncio async def test_modifing_the_instance(cleanup): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): @pre_update(Album) async def before_update(sender, instance, **kwargs): @@ -358,8 +339,8 @@ async def before_update(sender, instance, **kwargs): @pytest.mark.asyncio async def test_custom_signal(cleanup): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): async def after_update(sender, instance, **kwargs): if instance.play_count > 50 and not instance.is_best_seller: diff --git a/tests/test_signals/test_signals_for_relations.py b/tests/test_signals/test_signals_for_relations.py index 08ddcc130..5db964a06 100644 --- a/tests/test_signals/test_signals_for_relations.py +++ b/tests/test_signals/test_signals_for_relations.py @@ -1,11 +1,9 @@ from typing import Optional -import databases import ormar import pydantic import pytest import pytest_asyncio -import sqlalchemy from ormar import ( post_relation_add, post_relation_remove, @@ -13,18 +11,15 @@ pre_relation_remove, ) -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() + +base_ormar_config = create_config() class AuditLog(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="audits", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="audits") id: int = ormar.Integer(primary_key=True) event_type: str = ormar.String(max_length=100) @@ -32,33 +27,21 @@ class AuditLog(ormar.Model): class Cover(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="covers", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="covers") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=100) class Artist(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="artists", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="artists") id: int = ormar.Integer(name="artist_id", primary_key=True) name: str = ormar.String(name="fname", max_length=100) class Album(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="albums", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="albums") id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=100) @@ -66,26 +49,20 @@ class Album(ormar.Model): artists = ormar.ManyToMany(Artist) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) @pytest_asyncio.fixture(autouse=True, scope="function") async def cleanup(): yield - async with database: + async with base_ormar_config.database: await AuditLog.objects.delete(each=True) @pytest.mark.asyncio async def test_relation_signal_functions(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): @pre_relation_add([Album, Cover, Artist]) async def before_relation_add( diff --git a/tests/test_utils/test_queryset_utils.py b/tests/test_utils/test_queryset_utils.py index c57129e30..c5c86bd36 100644 --- a/tests/test_utils/test_queryset_utils.py +++ b/tests/test_utils/test_queryset_utils.py @@ -1,6 +1,4 @@ -import databases import ormar -import sqlalchemy from ormar.queryset.queries.prefetch_query import sort_models from ormar.queryset.utils import ( subtract_dict, @@ -9,7 +7,11 @@ update_dict_from_list, ) -from tests.settings import DATABASE_URL +from tests.settings import create_config +from tests.lifespan import init_tests + + +base_ormar_config = create_config() def test_list_to_dict_translation(): @@ -173,16 +175,8 @@ def test_subtracting_with_set_and_dict(): assert test == {"translation": {"translations": {"language": Ellipsis}}} -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - - class SortModel(ormar.Model): - ormar_config = ormar.OrmarConfig( - tablename="sorts", - metadata=metadata, - database=database, - ) + ormar_config = base_ormar_config.copy(tablename="sorts") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -212,3 +206,5 @@ def test_sorting_models(): orders_by = {"sort_order": "asc", "none": ..., "id": "asc", "uu": 2, "aa": None} models = sort_models(models, orders_by) assert [model.id for model in models] == [1, 4, 2, 3, 5, 6] + +create_test_database = init_tests(base_ormar_config) From 82580904d943f8a4bdc906940297f9129c85f3c7 Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 12 Feb 2024 18:30:06 +0100 Subject: [PATCH 78/95] check return types --- ormar/models/helpers/relations.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 5c94ecd04..4704f11d8 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -149,14 +149,14 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: annotation=field_type, default=None ) add_field_serializer_for_reverse_relations( - to_model=model_field.to, related_name=related_name + to_model=model_field.to, related_name=related_name, field_type=field_type ) model_field.to.model_rebuild(force=True) setattr(model_field.to, related_name, RelationDescriptor(name=related_name)) def add_field_serializer_for_reverse_relations( - to_model: Type["Model"], related_name: str + to_model: Type["Model"], related_name: str, field_type: type ) -> None: def serialize( self: "Model", children: List["Model"], handler: SerializerFunctionWrapHandler @@ -177,9 +177,9 @@ def serialize( result.append({child.ormar_config.pkname: child.pk}) return result - decorator = field_serializer(related_name, mode="wrap", check_fields=False)( - serialize - ) + decorator = field_serializer( + related_name, mode="wrap", check_fields=False, return_type=field_type + )(serialize) setattr(to_model, f"serialize_{related_name}", decorator) DecoratorInfos.build(to_model) From 217faaed5280f5d02783a62281e9aa78f474ddd8 Mon Sep 17 00:00:00 2001 From: collerek Date: Mon, 12 Feb 2024 23:31:57 +0100 Subject: [PATCH 79/95] fix imports order, set warnings=False on json that passes the dict, fix unnecessary loop in one of the test --- Makefile | 2 +- benchmarks/conftest.py | 4 +--- docs_src/fastapi/docs001.py | 4 +--- examples/fastapi_quick_start.py | 1 + ormar/models/newbasemodel.py | 4 ++-- ormar/models/ormar_config.py | 2 +- tests/lifespan.py | 6 +++--- tests/test_deferred/test_forward_cross_refs.py | 3 +-- tests/test_deferred/test_forward_refs.py | 3 +-- tests/test_deferred/test_more_same_table_joins.py | 3 +-- tests/test_deferred/test_same_table_joins.py | 3 +-- tests/test_encryption/test_encrypted_columns.py | 3 +-- .../test_complex_relation_tree_performance.py | 4 +--- .../test_dumping_model_to_dict.py | 3 +-- .../test_excludable_items.py | 2 +- .../test_excluding_fields_in_fastapi.py | 4 +--- .../test_excluding_fields_with_default.py | 3 +-- .../test_excluding_subset_of_columns.py | 3 +-- .../test_pydantic_dict_params.py | 3 +-- tests/test_fastapi/test_binary_fields.py | 5 ++--- .../test_docs_with_multiple_relations_to_one.py | 3 +-- tests/test_fastapi/test_enum_schema.py | 3 +-- tests/test_fastapi/test_excludes_with_get_pydantic.py | 6 +++--- tests/test_fastapi/test_excluding_fields.py | 3 +-- tests/test_fastapi/test_extra_ignore_parameter.py | 3 +-- tests/test_fastapi/test_fastapi_docs.py | 4 +--- tests/test_fastapi/test_fastapi_usage.py | 4 +--- .../test_fastapi/test_inheritance_concrete_fastapi.py | 6 ++---- tests/test_fastapi/test_inheritance_mixins_fastapi.py | 8 +++----- tests/test_fastapi/test_json_field_fastapi.py | 3 +-- tests/test_fastapi/test_m2m_forwardref.py | 4 +--- tests/test_fastapi/test_more_reallife_fastapi.py | 4 +--- tests/test_fastapi/test_nested_saving.py | 3 +-- tests/test_fastapi/test_recursion_error.py | 3 +-- .../test_relations_with_nested_defaults.py | 3 +-- tests/test_fastapi/test_schema_not_allowed_params.py | 3 --- tests/test_fastapi/test_skip_reverse_models.py | 4 +--- tests/test_fastapi/test_wekref_exclusion.py | 4 +--- .../test_excluding_parent_fields_inheritance.py | 3 +-- .../test_geting_pydantic_models.py | 5 +---- .../test_inheritance_concrete.py | 4 ++-- .../test_inheritance_mixins.py | 3 +-- .../test_inheritance_of_property_fields.py | 3 +-- .../test_inheritance_with_default.py | 3 +-- ...test_inherited_class_is_not_abstract_by_default.py | 5 +---- .../test_nested_models_pydantic.py | 3 +-- .../test_pydantic_fields_order.py | 3 +-- .../test_validators_are_inherited.py | 3 +-- .../test_validators_in_generated_pydantic.py | 3 +-- tests/test_meta_constraints/test_check_constraints.py | 3 +-- tests/test_meta_constraints/test_index_constraints.py | 3 +-- .../test_meta_constraints/test_unique_constraints.py | 3 +-- tests/test_model_definition/test_aliases.py | 3 +-- tests/test_model_definition/test_columns.py | 3 +-- .../test_create_uses_init_for_consistency.py | 3 +-- .../test_model_definition/test_dates_with_timezone.py | 3 +-- tests/test_model_definition/test_equality_and_hash.py | 3 +-- .../test_extra_ignore_parameter.py | 3 +-- tests/test_model_definition/test_fields_access.py | 5 +---- .../test_foreign_key_value_used_for_related_model.py | 3 +-- tests/test_model_definition/test_iterate.py | 3 +-- tests/test_model_definition/test_model_construct.py | 3 +-- tests/test_model_definition/test_model_definition.py | 3 +-- tests/test_model_definition/test_models.py | 3 +-- .../test_model_definition/test_models_are_pickable.py | 3 +-- .../test_overwriting_pydantic_field_type.py | 3 +-- .../test_overwriting_sql_nullable.py | 3 +-- .../test_pk_field_is_always_not_null.py | 3 +-- tests/test_model_definition/test_properties.py | 3 +-- tests/test_model_definition/test_pydantic_fields.py | 3 +-- .../test_pydantic_only_fields.py | 3 +-- .../test_pydantic_private_attributes.py | 3 +-- tests/test_model_definition/test_save_status.py | 3 +-- .../test_saving_nullable_fields.py | 3 +-- tests/test_model_definition/test_server_default.py | 3 +-- .../test_setting_comments_in_db.py | 3 +-- tests/test_model_methods/test_excludes_in_load_all.py | 3 +-- tests/test_model_methods/test_load_all.py | 3 +-- .../test_populate_default_values.py | 3 +-- tests/test_model_methods/test_save_related.py | 5 +---- .../test_model_methods/test_save_related_from_dict.py | 3 +-- tests/test_model_methods/test_save_related_uuid.py | 5 +---- tests/test_model_methods/test_update.py | 5 +---- tests/test_model_methods/test_upsert.py | 5 +---- tests/test_ordering/test_default_model_order.py | 3 +-- tests/test_ordering/test_default_relation_order.py | 3 +-- .../test_default_through_relation_order.py | 3 +-- .../test_proper_order_of_sorting_apply.py | 3 +-- tests/test_queries/test_adding_related.py | 3 +-- tests/test_queries/test_aggr_functions.py | 3 +-- tests/test_queries/test_deep_relations_select_all.py | 3 +-- tests/test_queries/test_filter_groups.py | 3 +-- tests/test_queries/test_indirect_relations_to_self.py | 3 +-- tests/test_queries/test_isnull_filter.py | 3 +-- tests/test_queries/test_nested_reverse_relations.py | 4 +--- .../test_non_relation_fields_not_merged.py | 3 +-- tests/test_queries/test_or_filters.py | 3 +-- tests/test_queries/test_order_by.py | 3 +-- tests/test_queries/test_pagination.py | 3 +-- tests/test_queries/test_queryproxy_on_m2m_models.py | 3 +-- tests/test_queries/test_queryset_level_methods.py | 3 +-- .../test_quoting_table_names_in_on_join_clause.py | 3 +-- .../test_reserved_sql_keywords_escaped.py | 3 +-- tests/test_queries/test_reverse_fk_queryset.py | 3 +-- .../test_queries/test_selecting_subset_of_columns.py | 3 +-- tests/test_queries/test_values_and_values_list.py | 3 +-- tests/test_relations/test_cascades.py | 3 +-- .../test_customizing_through_model_relation_names.py | 3 +-- tests/test_relations/test_database_fk_creation.py | 3 +-- tests/test_relations/test_foreign_keys.py | 3 +-- tests/test_relations/test_m2m_through_fields.py | 3 +-- tests/test_relations/test_many_to_many.py | 11 +---------- .../test_postgress_select_related_with_limit.py | 3 +-- tests/test_relations/test_prefetch_related.py | 3 +-- .../test_prefetch_related_multiple_models_relation.py | 3 +-- tests/test_relations/test_python_style_relations.py | 3 +-- .../test_relations_default_exception.py | 3 +-- .../test_relations/test_replacing_models_with_copy.py | 3 +-- tests/test_relations/test_saving_related.py | 3 +-- .../test_relations/test_select_related_with_limit.py | 3 +-- .../test_select_related_with_m2m_and_pk_name_set.py | 3 +-- .../test_selecting_proper_table_prefix.py | 3 +-- tests/test_relations/test_skipping_reverse.py | 3 +-- tests/test_relations/test_through_relations_fail.py | 3 +-- tests/test_relations/test_weakref_checking.py | 1 - tests/test_signals/test_signals.py | 3 +-- tests/test_signals/test_signals_for_relations.py | 3 +-- tests/test_utils/test_queryset_utils.py | 4 ++-- 128 files changed, 137 insertions(+), 292 deletions(-) diff --git a/Makefile b/Makefile index fa337fbc9..5b1f0e32c 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ test_docs: bash scripts/test_docs.sh -svv test: - pytest + pytest -svv tests/ coverage: pytest --cov=ormar --cov=tests --cov-fail-under=100 --cov-report=term-missing tests diff --git a/benchmarks/conftest.py b/benchmarks/conftest.py index 083ab4c5c..7105a0684 100644 --- a/benchmarks/conftest.py +++ b/benchmarks/conftest.py @@ -7,10 +7,8 @@ import ormar import pytest import pytest_asyncio - -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() nest_asyncio.apply() diff --git a/docs_src/fastapi/docs001.py b/docs_src/fastapi/docs001.py index 68ee72dba..a290a95f8 100644 --- a/docs_src/fastapi/docs001.py +++ b/docs_src/fastapi/docs001.py @@ -2,10 +2,8 @@ import ormar from fastapi import FastAPI - -from tests.settings import create_config from tests.lifespan import lifespan - +from tests.settings import create_config base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) diff --git a/examples/fastapi_quick_start.py b/examples/fastapi_quick_start.py index 5883b8e8a..01bb0118f 100644 --- a/examples/fastapi_quick_start.py +++ b/examples/fastapi_quick_start.py @@ -24,6 +24,7 @@ async def lifespan(app: FastAPI): if database_.is_connected: await database_.disconnect() + app = FastAPI(lifespan=lifespan) metadata = sqlalchemy.MetaData() database = databases.Database("sqlite:///test.db") diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 03743156f..366c8770d 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -891,7 +891,7 @@ def model_dump( # type: ignore # noqa A003 exclude_unset=exclude_unset, exclude_none=exclude_none, round_trip=round_trip, - warnings=warnings, + warnings=False, ) dict_instance = { @@ -994,7 +994,7 @@ def model_dump_json( # type: ignore # noqa A003 exclude_primary_keys=exclude_primary_keys, exclude_through_models=exclude_through_models, ) - return self.__pydantic_serializer__.to_json(data).decode() + return self.__pydantic_serializer__.to_json(data, warnings=False).decode() @classmethod @typing_extensions.deprecated( diff --git a/ormar/models/ormar_config.py b/ormar/models/ormar_config.py index e1895377e..e4941b18b 100644 --- a/ormar/models/ormar_config.py +++ b/ormar/models/ormar_config.py @@ -40,7 +40,7 @@ def __init__( self.pkname = None # type: ignore self.metadata = metadata self.database = database # type: ignore - self.engine = engine # type: ignore + self.engine = engine # type: ignore self.tablename = tablename # type: ignore self.orders_by = order_by or [] self.columns: List[sqlalchemy.Column] = [] diff --git a/tests/lifespan.py b/tests/lifespan.py index 684f358fd..afd786fc1 100644 --- a/tests/lifespan.py +++ b/tests/lifespan.py @@ -1,9 +1,9 @@ +from contextlib import asynccontextmanager +from typing import AsyncIterator + import pytest import sqlalchemy - -from contextlib import asynccontextmanager from fastapi import FastAPI -from typing import AsyncIterator def lifespan(config): diff --git a/tests/test_deferred/test_forward_cross_refs.py b/tests/test_deferred/test_forward_cross_refs.py index 56af4d776..8a87fc107 100644 --- a/tests/test_deferred/test_forward_cross_refs.py +++ b/tests/test_deferred/test_forward_cross_refs.py @@ -4,9 +4,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_deferred/test_forward_refs.py b/tests/test_deferred/test_forward_refs.py index 7842d37af..6208fa7fd 100644 --- a/tests/test_deferred/test_forward_refs.py +++ b/tests/test_deferred/test_forward_refs.py @@ -7,9 +7,8 @@ import sqlalchemy as sa from ormar.exceptions import ModelError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_deferred/test_more_same_table_joins.py b/tests/test_deferred/test_more_same_table_joins.py index 5cebb79d6..fc89f4094 100644 --- a/tests/test_deferred/test_more_same_table_joins.py +++ b/tests/test_deferred/test_more_same_table_joins.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_deferred/test_same_table_joins.py b/tests/test_deferred/test_same_table_joins.py index 548fded6b..2b0c9f89d 100644 --- a/tests/test_deferred/test_same_table_joins.py +++ b/tests/test_deferred/test_same_table_joins.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_encryption/test_encrypted_columns.py b/tests/test_encryption/test_encrypted_columns.py index 589886fd8..872fd4873 100644 --- a/tests/test_encryption/test_encrypted_columns.py +++ b/tests/test_encryption/test_encrypted_columns.py @@ -11,9 +11,8 @@ from ormar import ModelDefinitionError, NoMatch from ormar.fields.sqlalchemy_encrypted import EncryptedString -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() default_fernet = dict( diff --git a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py index a70c74c58..322974c69 100644 --- a/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py +++ b/tests/test_exclude_include_dict/test_complex_relation_tree_performance.py @@ -1,14 +1,12 @@ from datetime import datetime from typing import List, Optional, Union -import databases import ormar as orm import pydantic import pytest -import sqlalchemy -from tests.settings import create_config from tests.lifespan import init_tests +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py index 060b531c5..9c062cf8b 100644 --- a/tests/test_exclude_include_dict/test_dumping_model_to_dict.py +++ b/tests/test_exclude_include_dict/test_dumping_model_to_dict.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_exclude_include_dict/test_excludable_items.py b/tests/test_exclude_include_dict/test_excludable_items.py index e1fa142ff..a4338f501 100644 --- a/tests/test_exclude_include_dict/test_excludable_items.py +++ b/tests/test_exclude_include_dict/test_excludable_items.py @@ -3,8 +3,8 @@ import ormar from ormar.models.excludable import ExcludableItems -from tests.settings import create_config from tests.lifespan import init_tests +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py index 50120301e..cb2ce9470 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_in_fastapi.py @@ -2,7 +2,6 @@ import random import string -import databases import ormar import pydantic import pytest @@ -13,10 +12,9 @@ from ormar import post_save from pydantic import ConfigDict, computed_field -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) diff --git a/tests/test_exclude_include_dict/test_excluding_fields_with_default.py b/tests/test_exclude_include_dict/test_excluding_fields_with_default.py index 23c5f87be..92dff49e6 100644 --- a/tests/test_exclude_include_dict/test_excluding_fields_with_default.py +++ b/tests/test_exclude_include_dict/test_excluding_fields_with_default.py @@ -4,9 +4,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py index d3f3aa845..71fe6a915 100644 --- a/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py +++ b/tests/test_exclude_include_dict/test_excluding_subset_of_columns.py @@ -4,9 +4,8 @@ import pydantic import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_exclude_include_dict/test_pydantic_dict_params.py b/tests/test_exclude_include_dict/test_pydantic_dict_params.py index a16d97e3a..ca23f281d 100644 --- a/tests/test_exclude_include_dict/test_pydantic_dict_params.py +++ b/tests/test_exclude_include_dict/test_pydantic_dict_params.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_fastapi/test_binary_fields.py b/tests/test_fastapi/test_binary_fields.py index 3142cbd62..41343c669 100644 --- a/tests/test_fastapi/test_binary_fields.py +++ b/tests/test_fastapi/test_binary_fields.py @@ -1,7 +1,7 @@ import base64 import uuid from enum import Enum -from typing import List +from typing import List import ormar import pytest @@ -9,9 +9,8 @@ from fastapi import FastAPI from httpx import AsyncClient +from tests.lifespan import init_tests, lifespan from tests.settings import create_config -from tests.lifespan import lifespan, init_tests - headers = {"content-type": "application/json"} base_ormar_config = create_config() diff --git a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py index 943653f77..43df07240 100644 --- a/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py +++ b/tests/test_fastapi/test_docs_with_multiple_relations_to_one.py @@ -7,9 +7,8 @@ from fastapi import FastAPI from httpx import AsyncClient +from tests.lifespan import init_tests, lifespan from tests.settings import create_config -from tests.lifespan import lifespan, init_tests - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) diff --git a/tests/test_fastapi/test_enum_schema.py b/tests/test_fastapi/test_enum_schema.py index a6431128c..da1f7c027 100644 --- a/tests/test_fastapi/test_enum_schema.py +++ b/tests/test_fastapi/test_enum_schema.py @@ -2,9 +2,8 @@ import ormar -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_fastapi/test_excludes_with_get_pydantic.py b/tests/test_fastapi/test_excludes_with_get_pydantic.py index a06a6e365..73727eff9 100644 --- a/tests/test_fastapi/test_excludes_with_get_pydantic.py +++ b/tests/test_fastapi/test_excludes_with_get_pydantic.py @@ -1,13 +1,13 @@ +from typing import ForwardRef, Optional + import ormar import pytest from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from typing import ForwardRef, Optional +from tests.lifespan import init_tests, lifespan from tests.settings import create_config -from tests.lifespan import lifespan, init_tests - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) diff --git a/tests/test_fastapi/test_excluding_fields.py b/tests/test_fastapi/test_excluding_fields.py index 6c33a1711..c4f951199 100644 --- a/tests/test_fastapi/test_excluding_fields.py +++ b/tests/test_fastapi/test_excluding_fields.py @@ -6,7 +6,7 @@ from fastapi import FastAPI from httpx import AsyncClient -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config base_ormar_config = create_config() @@ -31,7 +31,6 @@ class Item(ormar.Model): create_test_database = init_tests(base_ormar_config) - @app.post("/items/", response_model=Item) async def create_item(item: Item): await item.save_related(follow=True, save_all=True) diff --git a/tests/test_fastapi/test_extra_ignore_parameter.py b/tests/test_fastapi/test_extra_ignore_parameter.py index 71b1219db..183ee2751 100644 --- a/tests/test_fastapi/test_extra_ignore_parameter.py +++ b/tests/test_fastapi/test_extra_ignore_parameter.py @@ -5,7 +5,7 @@ from httpx import AsyncClient from ormar import Extra -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config base_ormar_config = create_config() @@ -22,7 +22,6 @@ class Item(ormar.Model): create_test_database = init_tests(base_ormar_config) - @app.post("/item/", response_model=Item) async def create_item(item: Item): return await item.save() diff --git a/tests/test_fastapi/test_fastapi_docs.py b/tests/test_fastapi/test_fastapi_docs.py index 698a4ae35..ca1d8929d 100644 --- a/tests/test_fastapi/test_fastapi_docs.py +++ b/tests/test_fastapi/test_fastapi_docs.py @@ -9,10 +9,9 @@ from httpx import AsyncClient from pydantic import Field -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) @@ -49,7 +48,6 @@ class Item(ormar.Model): create_test_database = init_tests(base_ormar_config) - @app.get("/items/", response_model=List[Item]) async def get_items(): items = await Item.objects.select_related("categories").all() diff --git a/tests/test_fastapi/test_fastapi_usage.py b/tests/test_fastapi/test_fastapi_usage.py index ed2f9046e..ec32de1e2 100644 --- a/tests/test_fastapi/test_fastapi_usage.py +++ b/tests/test_fastapi/test_fastapi_usage.py @@ -6,9 +6,8 @@ from fastapi import FastAPI from httpx import AsyncClient +from tests.lifespan import init_tests, lifespan from tests.settings import create_config -from tests.lifespan import lifespan, init_tests - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) @@ -32,7 +31,6 @@ class Item(ormar.Model): create_test_database = init_tests(base_ormar_config) - @app.post("/items/", response_model=Item) async def create_item(item: Item): return item diff --git a/tests/test_fastapi/test_inheritance_concrete_fastapi.py b/tests/test_fastapi/test_inheritance_concrete_fastapi.py index 3504a4989..8a582fb7d 100644 --- a/tests/test_fastapi/test_inheritance_concrete_fastapi.py +++ b/tests/test_fastapi/test_inheritance_concrete_fastapi.py @@ -1,18 +1,17 @@ import datetime from typing import List, Optional -import pytest import ormar +import pytest from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient from ormar.relations.relation_proxy import RelationProxy from pydantic import computed_field -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) @@ -137,7 +136,6 @@ class Truck2(Car2): create_test_database = init_tests(base_ormar_config) - @app.post("/subjects/", response_model=Subject) async def create_item(item: Subject): return item diff --git a/tests/test_fastapi/test_inheritance_mixins_fastapi.py b/tests/test_fastapi/test_inheritance_mixins_fastapi.py index fa7289079..2c8c1838e 100644 --- a/tests/test_fastapi/test_inheritance_mixins_fastapi.py +++ b/tests/test_fastapi/test_inheritance_mixins_fastapi.py @@ -1,16 +1,15 @@ import datetime +from typing import Optional -import pytest import ormar +import pytest from asgi_lifespan import LifespanManager from fastapi import FastAPI from httpx import AsyncClient -from typing import Optional -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) @@ -44,7 +43,6 @@ class Subject(ormar.Model, DateFieldsMixins): create_test_database = init_tests(base_ormar_config) - @app.post("/subjects/", response_model=Subject) async def create_item(item: Subject): return item diff --git a/tests/test_fastapi/test_json_field_fastapi.py b/tests/test_fastapi/test_json_field_fastapi.py index 394e23e38..282c35371 100644 --- a/tests/test_fastapi/test_json_field_fastapi.py +++ b/tests/test_fastapi/test_json_field_fastapi.py @@ -9,10 +9,9 @@ from fastapi import FastAPI from httpx import AsyncClient -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) diff --git a/tests/test_fastapi/test_m2m_forwardref.py b/tests/test_fastapi/test_m2m_forwardref.py index 4d5e5f1f7..20c10bf41 100644 --- a/tests/test_fastapi/test_m2m_forwardref.py +++ b/tests/test_fastapi/test_m2m_forwardref.py @@ -7,10 +7,9 @@ from httpx import AsyncClient from starlette import status -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) @@ -54,7 +53,6 @@ class City(ormar.Model): create_test_database = init_tests(base_ormar_config) - @app.post("/", response_model=Country, status_code=status.HTTP_201_CREATED) async def create_country(country: Country): # if this is ormar result = await country.upsert() # it's already initialized as ormar model diff --git a/tests/test_fastapi/test_more_reallife_fastapi.py b/tests/test_fastapi/test_more_reallife_fastapi.py index 3540ad31c..fc9c08c5a 100644 --- a/tests/test_fastapi/test_more_reallife_fastapi.py +++ b/tests/test_fastapi/test_more_reallife_fastapi.py @@ -6,10 +6,9 @@ from fastapi import FastAPI from httpx import AsyncClient -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) @@ -32,7 +31,6 @@ class Item(ormar.Model): create_test_database = init_tests(base_ormar_config) - @app.get("/items", response_model=List[Item]) async def get_items(): items = await Item.objects.select_related("category").all() diff --git a/tests/test_fastapi/test_nested_saving.py b/tests/test_fastapi/test_nested_saving.py index e5827ca66..8b6992766 100644 --- a/tests/test_fastapi/test_nested_saving.py +++ b/tests/test_fastapi/test_nested_saving.py @@ -7,10 +7,9 @@ from httpx import AsyncClient from ormar.queryset.utils import translate_list_to_dict -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) headers = {"content-type": "application/json"} diff --git a/tests/test_fastapi/test_recursion_error.py b/tests/test_fastapi/test_recursion_error.py index 962d0a21e..ef6b91e6e 100644 --- a/tests/test_fastapi/test_recursion_error.py +++ b/tests/test_fastapi/test_recursion_error.py @@ -9,7 +9,7 @@ from httpx import AsyncClient from pydantic import BaseModel, Json -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config base_ormar_config = create_config() @@ -77,7 +77,6 @@ class Quiz(ormar.Model): create_test_database = init_tests(base_ormar_config) - async def get_current_user(): return await User(email="mail@example.com", username="aa", password="pass").save() diff --git a/tests/test_fastapi/test_relations_with_nested_defaults.py b/tests/test_fastapi/test_relations_with_nested_defaults.py index 6a7a4a8bd..ebbb6c77f 100644 --- a/tests/test_fastapi/test_relations_with_nested_defaults.py +++ b/tests/test_fastapi/test_relations_with_nested_defaults.py @@ -7,10 +7,9 @@ from fastapi import FastAPI from httpx import AsyncClient -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) diff --git a/tests/test_fastapi/test_schema_not_allowed_params.py b/tests/test_fastapi/test_schema_not_allowed_params.py index c5555802c..5147f9128 100644 --- a/tests/test_fastapi/test_schema_not_allowed_params.py +++ b/tests/test_fastapi/test_schema_not_allowed_params.py @@ -1,11 +1,8 @@ -import databases import ormar -import sqlalchemy from tests.lifespan import init_tests from tests.settings import create_config - base_ormar_config = create_config() diff --git a/tests/test_fastapi/test_skip_reverse_models.py b/tests/test_fastapi/test_skip_reverse_models.py index 5eef08573..fd06ae0a7 100644 --- a/tests/test_fastapi/test_skip_reverse_models.py +++ b/tests/test_fastapi/test_skip_reverse_models.py @@ -6,10 +6,9 @@ from fastapi import FastAPI from httpx import AsyncClient -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) headers = {"content-type": "application/json"} @@ -46,7 +45,6 @@ class Post(ormar.Model): create_test_database = init_tests(base_ormar_config) - @app.post("/categories/forbid/", response_model=Category2) async def create_category_forbid(category: Category2): # pragma: no cover pass diff --git a/tests/test_fastapi/test_wekref_exclusion.py b/tests/test_fastapi/test_wekref_exclusion.py index 6002dc484..bcaf5227f 100644 --- a/tests/test_fastapi/test_wekref_exclusion.py +++ b/tests/test_fastapi/test_wekref_exclusion.py @@ -8,10 +8,9 @@ from fastapi import FastAPI from httpx import AsyncClient -from tests.lifespan import lifespan, init_tests +from tests.lifespan import init_tests, lifespan from tests.settings import create_config - base_ormar_config = create_config() app = FastAPI(lifespan=lifespan(base_ormar_config)) @@ -36,7 +35,6 @@ class Thing(ormar.Model): create_test_database = init_tests(base_ormar_config) - @app.post("/test/1") async def post_test_1(): # don't split initialization and attribute assignment diff --git a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py index a50cd0977..a083a29cc 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py +++ b/tests/test_inheritance_and_pydantic_generation/test_excluding_parent_fields_inheritance.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py index b9f1e525c..5ca9a3e89 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py +++ b/tests/test_inheritance_and_pydantic_generation/test_geting_pydantic_models.py @@ -1,14 +1,11 @@ from typing import ForwardRef, List, Optional -import databases import ormar import pydantic -import sqlalchemy from pydantic_core import PydanticUndefined -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py index 6046e0e31..aa4d7756b 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_concrete.py @@ -13,12 +13,12 @@ from ormar.relations.relation_proxy import RelationProxy from pydantic import computed_field -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() + class AuditModel(ormar.Model): ormar_config = base_ormar_config.copy(abstract=True) diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py index 923c0c897..68a6b91dd 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_mixins.py @@ -5,9 +5,8 @@ import pytest import sqlalchemy as sa -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py index f8d9834ee..6b87cef3f 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_of_property_fields.py @@ -1,9 +1,8 @@ import ormar from pydantic import computed_field -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py index 900b0ffe3..bd93e79e0 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inheritance_with_default.py @@ -4,9 +4,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py b/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py index 44a75791d..0f4352521 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py +++ b/tests/test_inheritance_and_pydantic_generation/test_inherited_class_is_not_abstract_by_default.py @@ -1,13 +1,10 @@ import datetime -import databases import ormar import pytest -import sqlalchemy -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py index 87a2b7bad..b73698f70 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_nested_models_pydantic.py @@ -1,8 +1,7 @@ import ormar -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py index f4661338d..58bf96c94 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py +++ b/tests/test_inheritance_and_pydantic_generation/test_pydantic_fields_order.py @@ -1,8 +1,7 @@ import ormar -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py index 7afb2cb77..e6f1b5e7d 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py @@ -4,9 +4,8 @@ import pytest from pydantic import ValidationError, field_validator -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py index 96ebc17c6..b8fce0dd3 100644 --- a/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_in_generated_pydantic.py @@ -4,9 +4,8 @@ import pytest from pydantic import ValidationError, field_validator -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_meta_constraints/test_check_constraints.py b/tests/test_meta_constraints/test_check_constraints.py index 4af656464..88084c333 100644 --- a/tests/test_meta_constraints/test_check_constraints.py +++ b/tests/test_meta_constraints/test_check_constraints.py @@ -4,9 +4,8 @@ import ormar.fields.constraints import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_meta_constraints/test_index_constraints.py b/tests/test_meta_constraints/test_index_constraints.py index 291839628..e3a21908a 100644 --- a/tests/test_meta_constraints/test_index_constraints.py +++ b/tests/test_meta_constraints/test_index_constraints.py @@ -1,9 +1,8 @@ import ormar.fields.constraints import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_meta_constraints/test_unique_constraints.py b/tests/test_meta_constraints/test_unique_constraints.py index 64da9ad5b..d1abd91f4 100644 --- a/tests/test_meta_constraints/test_unique_constraints.py +++ b/tests/test_meta_constraints/test_unique_constraints.py @@ -5,9 +5,8 @@ import pymysql import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_aliases.py b/tests/test_model_definition/test_aliases.py index 13fbb530d..0bd3d1a81 100644 --- a/tests/test_model_definition/test_aliases.py +++ b/tests/test_model_definition/test_aliases.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_columns.py b/tests/test_model_definition/test_columns.py index 94b24f862..3fbf8f898 100644 --- a/tests/test_model_definition/test_columns.py +++ b/tests/test_model_definition/test_columns.py @@ -6,9 +6,8 @@ import pytest from ormar import ModelDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_model_definition/test_create_uses_init_for_consistency.py b/tests/test_model_definition/test_create_uses_init_for_consistency.py index 736248008..80cd7729f 100644 --- a/tests/test_model_definition/test_create_uses_init_for_consistency.py +++ b/tests/test_model_definition/test_create_uses_init_for_consistency.py @@ -5,9 +5,8 @@ import pytest from pydantic import model_validator -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_dates_with_timezone.py b/tests/test_model_definition/test_dates_with_timezone.py index 954ca350e..42917ecee 100644 --- a/tests/test_model_definition/test_dates_with_timezone.py +++ b/tests/test_model_definition/test_dates_with_timezone.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_equality_and_hash.py b/tests/test_model_definition/test_equality_and_hash.py index 0d46dadf0..f5b3cd335 100644 --- a/tests/test_model_definition/test_equality_and_hash.py +++ b/tests/test_model_definition/test_equality_and_hash.py @@ -2,9 +2,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_extra_ignore_parameter.py b/tests/test_model_definition/test_extra_ignore_parameter.py index 7f20cc503..733faf2b4 100644 --- a/tests/test_model_definition/test_extra_ignore_parameter.py +++ b/tests/test_model_definition/test_extra_ignore_parameter.py @@ -1,9 +1,8 @@ import ormar from ormar import Extra -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_model_definition/test_fields_access.py b/tests/test_model_definition/test_fields_access.py index c457f1438..538f8258c 100644 --- a/tests/test_model_definition/test_fields_access.py +++ b/tests/test_model_definition/test_fields_access.py @@ -1,12 +1,9 @@ -import databases import ormar import pytest -import sqlalchemy from ormar import BaseField -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py b/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py index 5ebc7f9bb..6f0e9b7b4 100644 --- a/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py +++ b/tests/test_model_definition/test_foreign_key_value_used_for_related_model.py @@ -4,9 +4,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_iterate.py b/tests/test_model_definition/test_iterate.py index c5a9f78f0..31e64ffd9 100644 --- a/tests/test_model_definition/test_iterate.py +++ b/tests/test_model_definition/test_iterate.py @@ -4,9 +4,8 @@ import pytest from ormar.exceptions import QueryDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_model_construct.py b/tests/test_model_definition/test_model_construct.py index 85ad4101d..b4f7ce385 100644 --- a/tests/test_model_definition/test_model_construct.py +++ b/tests/test_model_definition/test_model_construct.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_model_definition.py b/tests/test_model_definition/test_model_definition.py index 7d841bf18..d3ca604f0 100644 --- a/tests/test_model_definition/test_model_definition.py +++ b/tests/test_model_definition/test_model_definition.py @@ -10,9 +10,8 @@ from ormar.exceptions import ModelDefinitionError from ormar.models import Model -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index 951edafd1..452696e36 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -11,9 +11,8 @@ import sqlalchemy from ormar.exceptions import ModelError, NoMatch, QueryDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_models_are_pickable.py b/tests/test_model_definition/test_models_are_pickable.py index c0c90e1f0..4ce741548 100644 --- a/tests/test_model_definition/test_models_are_pickable.py +++ b/tests/test_model_definition/test_models_are_pickable.py @@ -4,9 +4,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_overwriting_pydantic_field_type.py b/tests/test_model_definition/test_overwriting_pydantic_field_type.py index bb026415d..d2d4fb0ae 100644 --- a/tests/test_model_definition/test_overwriting_pydantic_field_type.py +++ b/tests/test_model_definition/test_overwriting_pydantic_field_type.py @@ -4,9 +4,8 @@ import pytest from pydantic import Json, PositiveInt, ValidationError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_overwriting_sql_nullable.py b/tests/test_model_definition/test_overwriting_sql_nullable.py index f967f05bd..699292164 100644 --- a/tests/test_model_definition/test_overwriting_sql_nullable.py +++ b/tests/test_model_definition/test_overwriting_sql_nullable.py @@ -7,9 +7,8 @@ import pytest from sqlalchemy import text -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_pk_field_is_always_not_null.py b/tests/test_model_definition/test_pk_field_is_always_not_null.py index 285c82dc3..4737a4b08 100644 --- a/tests/test_model_definition/test_pk_field_is_always_not_null.py +++ b/tests/test_model_definition/test_pk_field_is_always_not_null.py @@ -1,8 +1,7 @@ import ormar -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_properties.py b/tests/test_model_definition/test_properties.py index 085f6e030..863f09387 100644 --- a/tests/test_model_definition/test_properties.py +++ b/tests/test_model_definition/test_properties.py @@ -3,9 +3,8 @@ import pytest from pydantic import PydanticUserError, computed_field -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_pydantic_fields.py b/tests/test_model_definition/test_pydantic_fields.py index ff9b1e474..8fec91c35 100644 --- a/tests/test_model_definition/test_pydantic_fields.py +++ b/tests/test_model_definition/test_pydantic_fields.py @@ -6,9 +6,8 @@ from pydantic import BaseModel, Field, HttpUrl from pydantic_extra_types.payment import PaymentCardNumber -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_pydantic_only_fields.py b/tests/test_model_definition/test_pydantic_only_fields.py index 024ecba3c..49800b015 100644 --- a/tests/test_model_definition/test_pydantic_only_fields.py +++ b/tests/test_model_definition/test_pydantic_only_fields.py @@ -5,9 +5,8 @@ import pytest from pydantic import computed_field -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_pydantic_private_attributes.py b/tests/test_model_definition/test_pydantic_private_attributes.py index 591dabaea..64d7f8340 100644 --- a/tests/test_model_definition/test_pydantic_private_attributes.py +++ b/tests/test_model_definition/test_pydantic_private_attributes.py @@ -3,9 +3,8 @@ import ormar from pydantic import PrivateAttr -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_save_status.py b/tests/test_model_definition/test_save_status.py index 52f58fb32..a2bab8f9b 100644 --- a/tests/test_model_definition/test_save_status.py +++ b/tests/test_model_definition/test_save_status.py @@ -4,9 +4,8 @@ import pytest from ormar.exceptions import ModelPersistenceError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_saving_nullable_fields.py b/tests/test_model_definition/test_saving_nullable_fields.py index 05a2a9405..456781405 100644 --- a/tests/test_model_definition/test_saving_nullable_fields.py +++ b/tests/test_model_definition/test_saving_nullable_fields.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_server_default.py b/tests/test_model_definition/test_server_default.py index 089d78463..a181d7905 100644 --- a/tests/test_model_definition/test_server_default.py +++ b/tests/test_model_definition/test_server_default.py @@ -5,9 +5,8 @@ import pytest from sqlalchemy import func, text -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_definition/test_setting_comments_in_db.py b/tests/test_model_definition/test_setting_comments_in_db.py index 08388be5c..30bc33693 100644 --- a/tests/test_model_definition/test_setting_comments_in_db.py +++ b/tests/test_model_definition/test_setting_comments_in_db.py @@ -2,9 +2,8 @@ import pytest from ormar.models import Model -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_methods/test_excludes_in_load_all.py b/tests/test_model_methods/test_excludes_in_load_all.py index 49811e386..6b9b08744 100644 --- a/tests/test_model_methods/test_excludes_in_load_all.py +++ b/tests/test_model_methods/test_excludes_in_load_all.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_model_methods/test_load_all.py b/tests/test_model_methods/test_load_all.py index af0452654..99d3ed2fb 100644 --- a/tests/test_model_methods/test_load_all.py +++ b/tests/test_model_methods/test_load_all.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_methods/test_populate_default_values.py b/tests/test_model_methods/test_populate_default_values.py index 820d313c1..8675f6794 100644 --- a/tests/test_model_methods/test_populate_default_values.py +++ b/tests/test_model_methods/test_populate_default_values.py @@ -1,9 +1,8 @@ import ormar from sqlalchemy import text -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_methods/test_save_related.py b/tests/test_model_methods/test_save_related.py index 7201050af..f12d3d158 100644 --- a/tests/test_model_methods/test_save_related.py +++ b/tests/test_model_methods/test_save_related.py @@ -1,13 +1,10 @@ from typing import List -import databases import ormar import pytest -import sqlalchemy -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_methods/test_save_related_from_dict.py b/tests/test_model_methods/test_save_related_from_dict.py index 089360ab5..c6a4e7ec9 100644 --- a/tests/test_model_methods/test_save_related_from_dict.py +++ b/tests/test_model_methods/test_save_related_from_dict.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_methods/test_save_related_uuid.py b/tests/test_model_methods/test_save_related_uuid.py index 2139cb573..5b425c680 100644 --- a/tests/test_model_methods/test_save_related_uuid.py +++ b/tests/test_model_methods/test_save_related_uuid.py @@ -1,14 +1,11 @@ import uuid from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_methods/test_update.py b/tests/test_model_methods/test_update.py index fbf11b823..f2cbd3398 100644 --- a/tests/test_model_methods/test_update.py +++ b/tests/test_model_methods/test_update.py @@ -1,13 +1,10 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_model_methods/test_upsert.py b/tests/test_model_methods/test_upsert.py index 43b241f1d..249054ce5 100644 --- a/tests/test_model_methods/test_upsert.py +++ b/tests/test_model_methods/test_upsert.py @@ -1,13 +1,10 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_ordering/test_default_model_order.py b/tests/test_ordering/test_default_model_order.py index 20bc4a608..4a7f4aacc 100644 --- a/tests/test_ordering/test_default_model_order.py +++ b/tests/test_ordering/test_default_model_order.py @@ -4,9 +4,8 @@ import pytest import pytest_asyncio -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_ordering/test_default_relation_order.py b/tests/test_ordering/test_default_relation_order.py index 6b20cc292..6e395a018 100644 --- a/tests/test_ordering/test_default_relation_order.py +++ b/tests/test_ordering/test_default_relation_order.py @@ -5,9 +5,8 @@ import pytest import pytest_asyncio -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_ordering/test_default_through_relation_order.py b/tests/test_ordering/test_default_through_relation_order.py index 1d0e1daa5..ed0889b76 100644 --- a/tests/test_ordering/test_default_through_relation_order.py +++ b/tests/test_ordering/test_default_through_relation_order.py @@ -12,9 +12,8 @@ pre_update, ) -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_ordering/test_proper_order_of_sorting_apply.py b/tests/test_ordering/test_proper_order_of_sorting_apply.py index 9f7c117b7..f6f805192 100644 --- a/tests/test_ordering/test_proper_order_of_sorting_apply.py +++ b/tests/test_ordering/test_proper_order_of_sorting_apply.py @@ -4,9 +4,8 @@ import pytest import pytest_asyncio -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_adding_related.py b/tests/test_queries/test_adding_related.py index 247999241..84a3f226b 100644 --- a/tests/test_queries/test_adding_related.py +++ b/tests/test_queries/test_adding_related.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_aggr_functions.py b/tests/test_queries/test_aggr_functions.py index c7986d783..ba8199dff 100644 --- a/tests/test_queries/test_aggr_functions.py +++ b/tests/test_queries/test_aggr_functions.py @@ -5,9 +5,8 @@ import pytest_asyncio from ormar.exceptions import QueryDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_deep_relations_select_all.py b/tests/test_queries/test_deep_relations_select_all.py index 3e7bc84f9..8e8eabc61 100644 --- a/tests/test_queries/test_deep_relations_select_all.py +++ b/tests/test_queries/test_deep_relations_select_all.py @@ -2,9 +2,8 @@ import pytest from sqlalchemy import func -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_filter_groups.py b/tests/test_queries/test_filter_groups.py index c0af4c8bf..5fd8c396f 100644 --- a/tests/test_queries/test_filter_groups.py +++ b/tests/test_queries/test_filter_groups.py @@ -2,9 +2,8 @@ import ormar -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_indirect_relations_to_self.py b/tests/test_queries/test_indirect_relations_to_self.py index ae4a91736..ca0e9a884 100644 --- a/tests/test_queries/test_indirect_relations_to_self.py +++ b/tests/test_queries/test_indirect_relations_to_self.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_isnull_filter.py b/tests/test_queries/test_isnull_filter.py index 4f7fc79ff..0f166caef 100644 --- a/tests/test_queries/test_isnull_filter.py +++ b/tests/test_queries/test_isnull_filter.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_nested_reverse_relations.py b/tests/test_queries/test_nested_reverse_relations.py index b55f11bcf..0c8069f4f 100644 --- a/tests/test_queries/test_nested_reverse_relations.py +++ b/tests/test_queries/test_nested_reverse_relations.py @@ -2,11 +2,9 @@ import ormar import pytest -import sqlalchemy -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_non_relation_fields_not_merged.py b/tests/test_queries/test_non_relation_fields_not_merged.py index 97b3c70a7..84500cb78 100644 --- a/tests/test_queries/test_non_relation_fields_not_merged.py +++ b/tests/test_queries/test_non_relation_fields_not_merged.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_or_filters.py b/tests/test_queries/test_or_filters.py index 05c2e556e..db61646b3 100644 --- a/tests/test_queries/test_or_filters.py +++ b/tests/test_queries/test_or_filters.py @@ -4,9 +4,8 @@ import pytest from ormar.exceptions import QueryDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_order_by.py b/tests/test_queries/test_order_by.py index 6c091805f..5f8ac9f81 100644 --- a/tests/test_queries/test_order_by.py +++ b/tests/test_queries/test_order_by.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_pagination.py b/tests/test_queries/test_pagination.py index 5215b9f89..790945b28 100644 --- a/tests/test_queries/test_pagination.py +++ b/tests/test_queries/test_pagination.py @@ -2,9 +2,8 @@ import pytest from ormar.exceptions import QueryDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_queryproxy_on_m2m_models.py b/tests/test_queries/test_queryproxy_on_m2m_models.py index 93a09b874..23de3d7b9 100644 --- a/tests/test_queries/test_queryproxy_on_m2m_models.py +++ b/tests/test_queries/test_queryproxy_on_m2m_models.py @@ -4,9 +4,8 @@ import pytest from ormar.exceptions import QueryDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_queryset_level_methods.py b/tests/test_queries/test_queryset_level_methods.py index 93805c28f..f223eb221 100644 --- a/tests/test_queries/test_queryset_level_methods.py +++ b/tests/test_queries/test_queryset_level_methods.py @@ -12,9 +12,8 @@ ) from pydantic import Json -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_queries/test_quoting_table_names_in_on_join_clause.py b/tests/test_queries/test_quoting_table_names_in_on_join_clause.py index 299246209..e74a9f698 100644 --- a/tests/test_queries/test_quoting_table_names_in_on_join_clause.py +++ b/tests/test_queries/test_quoting_table_names_in_on_join_clause.py @@ -5,9 +5,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_reserved_sql_keywords_escaped.py b/tests/test_queries/test_reserved_sql_keywords_escaped.py index ad0d3a45c..0998233a7 100644 --- a/tests/test_queries/test_reserved_sql_keywords_escaped.py +++ b/tests/test_queries/test_reserved_sql_keywords_escaped.py @@ -1,9 +1,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_queries/test_reverse_fk_queryset.py b/tests/test_queries/test_reverse_fk_queryset.py index 1a629b21e..28937084b 100644 --- a/tests/test_queries/test_reverse_fk_queryset.py +++ b/tests/test_queries/test_reverse_fk_queryset.py @@ -4,9 +4,8 @@ import pytest from ormar import NoMatch -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_selecting_subset_of_columns.py b/tests/test_queries/test_selecting_subset_of_columns.py index 90dc80550..d7b943981 100644 --- a/tests/test_queries/test_selecting_subset_of_columns.py +++ b/tests/test_queries/test_selecting_subset_of_columns.py @@ -7,9 +7,8 @@ import pytest import pytest_asyncio -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_queries/test_values_and_values_list.py b/tests/test_queries/test_values_and_values_list.py index bb67b38fe..c090e4ae5 100644 --- a/tests/test_queries/test_values_and_values_list.py +++ b/tests/test_queries/test_values_and_values_list.py @@ -6,9 +6,8 @@ import pytest_asyncio from ormar.exceptions import QueryDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_cascades.py b/tests/test_relations/test_cascades.py index a85e2a70b..22c079aeb 100644 --- a/tests/test_relations/test_cascades.py +++ b/tests/test_relations/test_cascades.py @@ -4,9 +4,8 @@ import pytest import pytest_asyncio -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_customizing_through_model_relation_names.py b/tests/test_relations/test_customizing_through_model_relation_names.py index 8a8f22204..1aa3630cc 100644 --- a/tests/test_relations/test_customizing_through_model_relation_names.py +++ b/tests/test_relations/test_customizing_through_model_relation_names.py @@ -1,9 +1,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_database_fk_creation.py b/tests/test_relations/test_database_fk_creation.py index 9566dcde5..390adcefd 100644 --- a/tests/test_relations/test_database_fk_creation.py +++ b/tests/test_relations/test_database_fk_creation.py @@ -5,9 +5,8 @@ import sqlalchemy from ormar.fields.foreign_key import validate_referential_action -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_foreign_keys.py b/tests/test_relations/test_foreign_keys.py index f3561c123..e77d9a1f1 100644 --- a/tests/test_relations/test_foreign_keys.py +++ b/tests/test_relations/test_foreign_keys.py @@ -4,9 +4,8 @@ import pytest from ormar.exceptions import MultipleMatches, NoMatch, RelationshipInstanceError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_m2m_through_fields.py b/tests/test_relations/test_m2m_through_fields.py index 99eacf0dd..82b1d6262 100644 --- a/tests/test_relations/test_m2m_through_fields.py +++ b/tests/test_relations/test_m2m_through_fields.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_relations/test_many_to_many.py b/tests/test_relations/test_many_to_many.py index ad1a6fb40..e52b56073 100644 --- a/tests/test_relations/test_many_to_many.py +++ b/tests/test_relations/test_many_to_many.py @@ -1,4 +1,3 @@ -import asyncio from typing import List, Optional import ormar @@ -6,9 +5,8 @@ import pytest_asyncio from ormar.exceptions import ModelPersistenceError, NoMatch, RelationshipInstanceError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) @@ -37,13 +35,6 @@ class Post(ormar.Model): author: Optional[Author] = ormar.ForeignKey(Author) -@pytest.fixture(scope="module") -def event_loop(): - loop = asyncio.get_event_loop() - yield loop - loop.close() - - create_test_database = init_tests(base_ormar_config) diff --git a/tests/test_relations/test_postgress_select_related_with_limit.py b/tests/test_relations/test_postgress_select_related_with_limit.py index 93b4e0914..a12d5b009 100644 --- a/tests/test_relations/test_postgress_select_related_with_limit.py +++ b/tests/test_relations/test_postgress_select_related_with_limit.py @@ -7,9 +7,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_relations/test_prefetch_related.py b/tests/test_relations/test_prefetch_related.py index 5a2dc245a..cb7b17dce 100644 --- a/tests/test_relations/test_prefetch_related.py +++ b/tests/test_relations/test_prefetch_related.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config(force_rollback=True) diff --git a/tests/test_relations/test_prefetch_related_multiple_models_relation.py b/tests/test_relations/test_prefetch_related_multiple_models_relation.py index ecaf722fc..2ffbab2e4 100644 --- a/tests/test_relations/test_prefetch_related_multiple_models_relation.py +++ b/tests/test_relations/test_prefetch_related_multiple_models_relation.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_python_style_relations.py b/tests/test_relations/test_python_style_relations.py index d9287ff4b..bfdb4b12b 100644 --- a/tests/test_relations/test_python_style_relations.py +++ b/tests/test_relations/test_python_style_relations.py @@ -4,9 +4,8 @@ import pytest import pytest_asyncio -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_relations_default_exception.py b/tests/test_relations/test_relations_default_exception.py index 2066caf33..0e18ca130 100644 --- a/tests/test_relations/test_relations_default_exception.py +++ b/tests/test_relations/test_relations_default_exception.py @@ -5,9 +5,8 @@ import pytest from ormar.exceptions import ModelDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_replacing_models_with_copy.py b/tests/test_relations/test_replacing_models_with_copy.py index 436a7006b..cf70e3388 100644 --- a/tests/test_relations/test_replacing_models_with_copy.py +++ b/tests/test_relations/test_replacing_models_with_copy.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_saving_related.py b/tests/test_relations/test_saving_related.py index 2c777a457..24668b905 100644 --- a/tests/test_relations/test_saving_related.py +++ b/tests/test_relations/test_saving_related.py @@ -4,9 +4,8 @@ import pytest from ormar.exceptions import ModelPersistenceError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_select_related_with_limit.py b/tests/test_relations/test_select_related_with_limit.py index 1be283a26..2bbe4eebe 100644 --- a/tests/test_relations/test_select_related_with_limit.py +++ b/tests/test_relations/test_select_related_with_limit.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py b/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py index 0f9beebbc..5ebaef7ad 100644 --- a/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py +++ b/tests/test_relations/test_select_related_with_m2m_and_pk_name_set.py @@ -7,9 +7,8 @@ import sqlalchemy from ormar import ModelDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_selecting_proper_table_prefix.py b/tests/test_relations/test_selecting_proper_table_prefix.py index b0de7e05a..9dfe3cdbb 100644 --- a/tests/test_relations/test_selecting_proper_table_prefix.py +++ b/tests/test_relations/test_selecting_proper_table_prefix.py @@ -3,9 +3,8 @@ import ormar import pytest -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_skipping_reverse.py b/tests/test_relations/test_skipping_reverse.py index 3cc49df8f..947741c49 100644 --- a/tests/test_relations/test_skipping_reverse.py +++ b/tests/test_relations/test_skipping_reverse.py @@ -4,9 +4,8 @@ import pytest import pytest_asyncio -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_through_relations_fail.py b/tests/test_relations/test_through_relations_fail.py index 5057d907b..e6fcfefab 100644 --- a/tests/test_relations/test_through_relations_fail.py +++ b/tests/test_relations/test_through_relations_fail.py @@ -4,9 +4,8 @@ import pytest from ormar import ModelDefinitionError -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_relations/test_weakref_checking.py b/tests/test_relations/test_weakref_checking.py index 3a666bbae..2af76200a 100644 --- a/tests/test_relations/test_weakref_checking.py +++ b/tests/test_relations/test_weakref_checking.py @@ -2,7 +2,6 @@ from tests.settings import create_config - base_ormar_config = create_config() from tests.lifespan import init_tests diff --git a/tests/test_signals/test_signals.py b/tests/test_signals/test_signals.py index 5e6405b8c..7a9f7e0e2 100644 --- a/tests/test_signals/test_signals.py +++ b/tests/test_signals/test_signals.py @@ -16,9 +16,8 @@ from ormar.exceptions import SignalDefinitionError from ormar.signals import SignalEmitter -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_signals/test_signals_for_relations.py b/tests/test_signals/test_signals_for_relations.py index 5db964a06..2ac2e23d3 100644 --- a/tests/test_signals/test_signals_for_relations.py +++ b/tests/test_signals/test_signals_for_relations.py @@ -11,9 +11,8 @@ pre_relation_remove, ) -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() diff --git a/tests/test_utils/test_queryset_utils.py b/tests/test_utils/test_queryset_utils.py index c5c86bd36..8c6320b37 100644 --- a/tests/test_utils/test_queryset_utils.py +++ b/tests/test_utils/test_queryset_utils.py @@ -7,9 +7,8 @@ update_dict_from_list, ) -from tests.settings import create_config from tests.lifespan import init_tests - +from tests.settings import create_config base_ormar_config = create_config() @@ -207,4 +206,5 @@ def test_sorting_models(): models = sort_models(models, orders_by) assert [model.id for model in models] == [1, 4, 2, 3, 5, 6] + create_test_database = init_tests(base_ormar_config) From cdce29db89f287c96c71f2342a57c962f4172159 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 18 Feb 2024 20:38:05 +0100 Subject: [PATCH 80/95] remove references to model's meta as it's now ormar config, rename related methods too --- docs_src/models/docs006.py | 2 +- docs_src/models/docs017.py | 2 +- docs_src/models/docs018.py | 2 +- examples/script_from_readme.py | 4 +- ormar/fields/many_to_many.py | 4 +- ormar/models/helpers/__init__.py | 12 ++-- ormar/models/helpers/models.py | 6 +- ormar/models/helpers/sqlalchemy.py | 53 +++++++++-------- ormar/models/metaclass.py | 59 ++++++++++--------- ormar/models/newbasemodel.py | 12 ++-- ormar/queryset/join.py | 4 +- ormar/queryset/queries/query.py | 4 +- ormar/queryset/queryset.py | 28 ++++----- ormar/relations/querysetproxy.py | 2 +- ormar/signals/__init__.py | 2 +- ...ustomizing_through_model_relation_names.py | 10 ++-- 16 files changed, 106 insertions(+), 100 deletions(-) diff --git a/docs_src/models/docs006.py b/docs_src/models/docs006.py index 91b9a7726..535aa13fe 100644 --- a/docs_src/models/docs006.py +++ b/docs_src/models/docs006.py @@ -10,7 +10,7 @@ class Course(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, - # define your constraints in Meta class of the model + # define your constraints in OrmarConfig of the model # it's a list that can contain multiple constraints # hera a combination of name and column will have to be unique in db constraints=[ormar.UniqueColumns("name", "completed")], diff --git a/docs_src/models/docs017.py b/docs_src/models/docs017.py index 4cc9abc58..464b1eb54 100644 --- a/docs_src/models/docs017.py +++ b/docs_src/models/docs017.py @@ -10,7 +10,7 @@ class Course(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, - # define your constraints in Meta class of the model + # define your constraints in OrmarConfig of the model # it's a list that can contain multiple constraints # hera a combination of name and column will have a compound index in the db constraints=[ormar.IndexColumns("name", "completed")], diff --git a/docs_src/models/docs018.py b/docs_src/models/docs018.py index 3fdfe03a2..7ef298845 100644 --- a/docs_src/models/docs018.py +++ b/docs_src/models/docs018.py @@ -12,7 +12,7 @@ class Course(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, - # define your constraints in Meta class of the model + # define your constraints in OrmarConfig of the model # it's a list that can contain multiple constraints # hera a combination of name and column will have a level check in the db constraints=[ diff --git a/examples/script_from_readme.py b/examples/script_from_readme.py index 841bbd3d3..936ddc395 100644 --- a/examples/script_from_readme.py +++ b/examples/script_from_readme.py @@ -10,8 +10,8 @@ metadata = sqlalchemy.MetaData() -# note that this step is optional -> all ormar cares is a internal -# class with name Meta and proper parameters, but this way you do not +# note that this step is optional -> all ormar cares is an individual +# OrmarConfig for each of the models, but this way you do not # have to repeat the same parameters if you use only one database base_ormar_config = ormar.OrmarConfig( metadata=metadata, diff --git a/ormar/fields/many_to_many.py b/ormar/fields/many_to_many.py index 1d757b6d9..1a8af2da6 100644 --- a/ormar/fields/many_to_many.py +++ b/ormar/fields/many_to_many.py @@ -280,7 +280,7 @@ def create_default_through_model(self) -> None: "__module__": self.owner.__module__, "__qualname__": f"{self.owner.__qualname__}.{class_name}", } - new_meta = ormar.models.ormar_config.OrmarConfig( + new_config = ormar.models.ormar_config.OrmarConfig( tablename=table_name, database=self.owner.ormar_config.database, metadata=self.owner.ormar_config.metadata, @@ -290,7 +290,7 @@ def create_default_through_model(self) -> None: (ormar.Model,), { **base_namespace, - "ormar_config": new_meta, + "ormar_config": new_config, "id": ormar.Integer(name="id", primary_key=True), }, ) diff --git a/ormar/models/helpers/__init__.py b/ormar/models/helpers/__init__.py index 8b5662b0b..5d4c1de74 100644 --- a/ormar/models/helpers/__init__.py +++ b/ormar/models/helpers/__init__.py @@ -1,5 +1,5 @@ from ormar.models.helpers.models import ( - check_required_meta_parameters, + check_required_config_parameters, config_field_not_set, extract_annotations_and_default_vals, populate_default_options_values, @@ -16,8 +16,8 @@ register_relation_in_alias_manager, ) from ormar.models.helpers.sqlalchemy import ( - populate_meta_sqlalchemy_table_if_required, - populate_meta_tablename_columns_and_pk, + populate_config_sqlalchemy_table_if_required, + populate_config_tablename_columns_and_pk, sqlalchemy_columns_from_model_fields, ) from ormar.models.helpers.validation import modify_schema_example @@ -25,15 +25,15 @@ __all__ = [ "expand_reverse_relationships", "extract_annotations_and_default_vals", - "populate_meta_tablename_columns_and_pk", - "populate_meta_sqlalchemy_table_if_required", + "populate_config_tablename_columns_and_pk", + "populate_config_sqlalchemy_table_if_required", "populate_default_options_values", "alias_manager", "register_relation_in_alias_manager", "get_potential_fields", "get_pydantic_base_orm_config", "merge_or_generate_pydantic_config", - "check_required_meta_parameters", + "check_required_config_parameters", "sqlalchemy_columns_from_model_fields", "config_field_not_set", "remove_excluded_parent_fields", diff --git a/ormar/models/helpers/models.py b/ormar/models/helpers/models.py index d9c8af008..e05ed16a9 100644 --- a/ormar/models/helpers/models.py +++ b/ormar/models/helpers/models.py @@ -31,7 +31,7 @@ def populate_default_options_values( # noqa: CCR001 new_model: Type["Model"], model_fields: Dict ) -> None: """ - Sets all optional Meta values to it's defaults + Sets all optional OrmarConfig values to its defaults and set model_fields that were already previously extracted. Here should live all options that are not overwritten/set for all models. @@ -83,7 +83,7 @@ def substitue_backend_pool_for_sqlite(new_model: Type["Model"]) -> None: backend._pool = old_pool.__class__(backend._database_url, **backend._options) -def check_required_meta_parameters(new_model: Type["Model"]) -> None: +def check_required_config_parameters(new_model: Type["Model"]) -> None: """ Verifies if ormar.Model has database and metadata set. @@ -155,7 +155,7 @@ def group_related_list(list_: List) -> Dict: def config_field_not_set(model: Type["Model"], field_name: str) -> bool: """ - Checks if field with given name is already present in model.Meta. + Checks if field with given name is already present in model.OrmarConfig. Then check if it's set to something truthful (in practice meaning not None, as it's non or ormar Field only). diff --git a/ormar/models/helpers/sqlalchemy.py b/ormar/models/helpers/sqlalchemy.py index fdcdfd35a..1a4fd974d 100644 --- a/ormar/models/helpers/sqlalchemy.py +++ b/ormar/models/helpers/sqlalchemy.py @@ -63,7 +63,8 @@ def create_and_append_m2m_fk( """ Registers sqlalchemy Column with sqlalchemy.ForeignKey leading to the model. - Newly created field is added to m2m relation through model Meta columns and table. + Newly created field is added to m2m relation + through model OrmarConfig columns and table. :param field_name: name of the column to create :type field_name: str @@ -208,14 +209,14 @@ def _is_db_field(field: "BaseField") -> bool: return not field.virtual and not field.is_multi -def populate_meta_tablename_columns_and_pk( +def populate_config_tablename_columns_and_pk( name: str, new_model: Type["Model"] ) -> Type["Model"]: """ - Sets Model tablename if it's not already set in Meta. + Sets Model tablename if it's not already set in OrmarConfig. Default tablename if not present is class name lower + s (i.e. Bed becomes -> beds) - Checks if Model's Meta have pkname and columns set. + Checks if Model's OrmarConfig have pkname and columns set. If not calls the sqlalchemy_columns_from_model_fields to populate columns from ormar.fields definitions. @@ -226,7 +227,7 @@ def populate_meta_tablename_columns_and_pk( :type name: str :param new_model: currently constructed Model :type new_model: ormar.models.metaclass.ModelMetaclass - :return: Model with populated pkname and columns in Meta + :return: Model with populated pkname and columns in OrmarConfig :rtype: ormar.models.metaclass.ModelMetaclass """ tablename = name.lower() + "s" @@ -251,52 +252,54 @@ def populate_meta_tablename_columns_and_pk( new_model.ormar_config.columns = columns new_model.ormar_config.pkname = pkname if not new_model.ormar_config.orders_by: - # by default we sort by pk name if other option not provided + # by default, we sort by pk name if other option not provided new_model.ormar_config.orders_by.append(pkname) return new_model -def check_for_null_type_columns_from_forward_refs(meta: "OrmarConfig") -> bool: +def check_for_null_type_columns_from_forward_refs(config: "OrmarConfig") -> bool: """ Check is any column is of NUllType() meaning it's empty column from ForwardRef - :param meta: Meta class of the Model without sqlalchemy table constructed - :type meta: Model class Meta + :param config: OrmarConfig of the Model without sqlalchemy table constructed + :type config: Model class OrmarConfig :return: result of the check :rtype: bool """ return not any( - isinstance(col.type, sqlalchemy.sql.sqltypes.NullType) for col in meta.columns + isinstance(col.type, sqlalchemy.sql.sqltypes.NullType) for col in config.columns ) -def populate_meta_sqlalchemy_table_if_required(meta: "OrmarConfig") -> None: +def populate_config_sqlalchemy_table_if_required(config: "OrmarConfig") -> None: """ - Constructs sqlalchemy table out of columns and parameters set on Meta class. + Constructs sqlalchemy table out of columns and parameters set on OrmarConfig. It populates name, metadata, columns and constraints. - :param meta: Meta class of the Model without sqlalchemy table constructed - :type meta: Model class Meta + :param config: OrmarConfig of the Model without sqlalchemy table constructed + :type config: Model class OrmarConfig """ - if meta.table is None and check_for_null_type_columns_from_forward_refs(meta): - set_constraint_names(meta=meta) + if config.table is None and check_for_null_type_columns_from_forward_refs( + config=config + ): + set_constraint_names(config=config) table = sqlalchemy.Table( - meta.tablename, meta.metadata, *meta.columns, *meta.constraints + config.tablename, config.metadata, *config.columns, *config.constraints ) - meta.table = table + config.table = table -def set_constraint_names(meta: "OrmarConfig") -> None: +def set_constraint_names(config: "OrmarConfig") -> None: """ Populates the names on IndexColumns and UniqueColumns and CheckColumns constraints. - :param meta: Meta class of the Model without sqlalchemy table constructed - :type meta: Model class Meta + :param config: OrmarConfig of the Model without sqlalchemy table constructed + :type config: Model class OrmarConfig """ - for constraint in meta.constraints: + for constraint in config.constraints: if isinstance(constraint, sqlalchemy.UniqueConstraint) and not constraint.name: constraint.name = ( - f"uc_{meta.tablename}_" + f"uc_{config.tablename}_" f'{"_".join([str(col) for col in constraint._pending_colargs])}' ) elif ( @@ -304,12 +307,12 @@ def set_constraint_names(meta: "OrmarConfig") -> None: and constraint.name == "TEMPORARY_NAME" ): constraint.name = ( - f"ix_{meta.tablename}_" + f"ix_{config.tablename}_" f'{"_".join([col for col in constraint._pending_colargs])}' ) elif isinstance(constraint, sqlalchemy.CheckConstraint) and not constraint.name: sql_condition: str = str(constraint.sqltext).replace(" ", "_") - constraint.name = f"check_{meta.tablename}_{sql_condition}" + constraint.name = f"check_{config.tablename}_{sql_condition}" def update_column_definition( diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index f46f8a0d1..348098e0d 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -40,16 +40,16 @@ ) from ormar.models.descriptors.descriptors import BytesDescriptor from ormar.models.helpers import ( - check_required_meta_parameters, + check_required_config_parameters, config_field_not_set, expand_reverse_relationships, extract_annotations_and_default_vals, get_potential_fields, merge_or_generate_pydantic_config, modify_schema_example, + populate_config_sqlalchemy_table_if_required, + populate_config_tablename_columns_and_pk, populate_default_options_values, - populate_meta_sqlalchemy_table_if_required, - populate_meta_tablename_columns_and_pk, register_relation_in_alias_manager, remove_excluded_parent_fields, sqlalchemy_columns_from_model_fields, @@ -119,7 +119,7 @@ def add_property_fields(new_model: Type["Model"], attrs: Dict) -> None: # noqa: def register_signals(new_model: Type["Model"]) -> None: # noqa: CCR001 """ - Registers on model's SignalEmmiter and sets pre defined signals. + Registers on model's SignalEmmiter and sets pre-defined signals. Predefined signals are (pre/post) + (save/update/delete). Signals are emitted in both model own methods and in selected queryset ones. @@ -202,11 +202,11 @@ def get_constraint_copy( return constructor(constraint) -def update_attrs_from_base_meta( # noqa: CCR001 +def update_attrs_from_base_config( # noqa: CCR001 base_class: "Model", attrs: Dict, model_fields: Dict ) -> None: """ - Updates Meta parameters in child from parent if needed. + Updates OrmarConfig parameters in child from parent if needed. :param base_class: one of the parent classes :type base_class: Model or model parent class @@ -288,7 +288,7 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 field.owner = base_class field.create_default_through_model() through_class = field.through - new_meta = ormar.OrmarConfig( + new_config = ormar.OrmarConfig( tablename=through_class.ormar_config.tablename, metadata=through_class.ormar_config.metadata, database=through_class.ormar_config.database, @@ -299,32 +299,34 @@ def copy_and_replace_m2m_through_model( # noqa: CFQ002 constraints=through_class.ormar_config.constraints, order_by=through_class.ormar_config.orders_by, ) - new_meta.table = through_class.ormar_config.pkname - new_meta.pkname = through_class.ormar_config.pkname - new_meta.alias_manager = through_class.ormar_config.alias_manager - new_meta.signals = through_class.ormar_config.signals - new_meta.requires_ref_update = through_class.ormar_config.requires_ref_update - new_meta.model_fields = copy.deepcopy(through_class.ormar_config.model_fields) - new_meta.property_fields = copy.deepcopy(through_class.ormar_config.property_fields) + new_config.table = through_class.ormar_config.pkname + new_config.pkname = through_class.ormar_config.pkname + new_config.alias_manager = through_class.ormar_config.alias_manager + new_config.signals = through_class.ormar_config.signals + new_config.requires_ref_update = through_class.ormar_config.requires_ref_update + new_config.model_fields = copy.deepcopy(through_class.ormar_config.model_fields) + new_config.property_fields = copy.deepcopy( + through_class.ormar_config.property_fields + ) copy_name = through_class.__name__ + attrs.get("__name__", "") copy_through = cast( - Type[ormar.Model], type(copy_name, (ormar.Model,), {"ormar_config": new_meta}) + Type[ormar.Model], type(copy_name, (ormar.Model,), {"ormar_config": new_config}) ) # create new table with copied columns but remove foreign keys # they will be populated later in expanding reverse relation - # if hasattr(new_meta, "table"): - new_meta.tablename += "_" + ormar_config.tablename - new_meta.table = None - new_meta.model_fields = { + # if hasattr(new_config, "table"): + new_config.tablename += "_" + ormar_config.tablename + new_config.table = None + new_config.model_fields = { name: field - for name, field in new_meta.model_fields.items() + for name, field in new_config.model_fields.items() if not field.is_relation } _, columns = sqlalchemy_columns_from_model_fields( - new_meta.model_fields, copy_through + new_config.model_fields, copy_through ) # type: ignore - new_meta.columns = columns - populate_meta_sqlalchemy_table_if_required(new_meta) + new_config.columns = columns + populate_config_sqlalchemy_table_if_required(config=new_config) copy_field.through = copy_through parent_fields[field_name] = copy_field @@ -366,7 +368,7 @@ def copy_data_from_parent_model( # noqa: CCR001 f"{curr_class.__name__} cannot inherit " f"from non abstract class {base_class.__name__}" ) - update_attrs_from_base_meta( + update_attrs_from_base_config( base_class=base_class, # type: ignore attrs=attrs, model_fields=model_fields, @@ -595,13 +597,14 @@ def __new__( # type: ignore # noqa: CCR001 Construct parent pydantic Metaclass/ Model. - If class has Meta class declared (so actual ormar Models) it also: + If class has ormar_config declared (so actual ormar Models) it also: * populate sqlalchemy columns, pkname and tables from model_fields * register reverse relationships on related models * registers all relations in alias manager that populates table_prefixes * exposes alias manager on each Model * creates QuerySet for each model and exposes it on a class + * sets custom serializers for relation models :param name: name of current class :type name: str @@ -645,14 +648,14 @@ def __new__( # type: ignore # noqa: CCR001 if hasattr(new_model, "ormar_config"): populate_default_options_values(new_model, model_fields) - check_required_meta_parameters(new_model) + check_required_config_parameters(new_model) add_property_fields(new_model, attrs) register_signals(new_model=new_model) modify_schema_example(model=new_model) if not new_model.ormar_config.abstract: - new_model = populate_meta_tablename_columns_and_pk(name, new_model) - populate_meta_sqlalchemy_table_if_required(new_model.ormar_config) + new_model = populate_config_tablename_columns_and_pk(name, new_model) + populate_config_sqlalchemy_table_if_required(new_model.ormar_config) expand_reverse_relationships(new_model) for field_name, field in new_model.ormar_config.model_fields.items(): register_relation_in_alias_manager(field=field) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 366c8770d..41d180f25 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -31,7 +31,7 @@ from ormar.models.helpers import register_relation_in_alias_manager from ormar.models.helpers.relations import expand_reverse_relationship from ormar.models.helpers.sqlalchemy import ( - populate_meta_sqlalchemy_table_if_required, + populate_config_sqlalchemy_table_if_required, update_column_definition, ) from ormar.models.metaclass import ModelMetaclass @@ -109,7 +109,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # type: ignore Json fields are automatically loaded/dumped if needed. - Models marked as abstract=True in internal Meta class cannot be initialized. + Models marked as abstract=True in internal OrmarConfig cannot be initialized. Accepts also special __pk_only__ flag that indicates that Model is constructed only with primary key value (so no other fields, it's a child model on other @@ -439,7 +439,7 @@ def get_name(cls, lower: bool = True) -> str: @property def pk_column(self) -> sqlalchemy.Column: """ - Retrieves primary key sqlalchemy column from models Meta.table. + Retrieves primary key sqlalchemy column from models OrmarConfig.table. Each model has to have primary key. Only one primary key column is allowed. @@ -460,7 +460,7 @@ def saved(self) -> bool: @property def signals(self) -> "SignalEmitter": - """Exposes signals from model Meta""" + """Exposes signals from model OrmarConfig""" return self.ormar_config.signals @classmethod @@ -517,7 +517,7 @@ def update_forward_refs(cls, **localns: Any) -> None: Expands relationships, register relation in alias manager and substitutes sqlalchemy columns with new ones with proper column type (null before). - Populates Meta table of the Model which is left empty before. + Populates OrmarConfig table of the Model which is left empty before. Sets self_reference flag on models that links to themselves. @@ -542,7 +542,7 @@ def update_forward_refs(cls, **localns: Any) -> None: expand_reverse_relationship(model_field=field) register_relation_in_alias_manager(field=field) update_column_definition(model=cls, field=field) - populate_meta_sqlalchemy_table_if_required(meta=cls.ormar_config) + populate_config_sqlalchemy_table_if_required(config=cls.ormar_config) # super().update_forward_refs(**localns) cls.model_rebuild(force=True) cls.ormar_config.requires_ref_update = False diff --git a/ormar/queryset/join.py b/ormar/queryset/join.py index acbd79176..3fd1f17fb 100644 --- a/ormar/queryset/join.py +++ b/ormar/queryset/join.py @@ -78,9 +78,9 @@ def next_alias(self, value: str) -> None: @property def alias_manager(self) -> AliasManager: """ - Shortcut for ormar's model AliasManager stored on Meta. + Shortcut for ormar's model AliasManager stored on OrmarConfig. - :return: alias manager from model's Meta + :return: alias manager from model's OrmarConfig :rtype: AliasManager """ return self.main_model.ormar_config.alias_manager diff --git a/ormar/queryset/queries/query.py b/ormar/queryset/queries/query.py index c53b1365a..87c89ea58 100644 --- a/ormar/queryset/queries/query.py +++ b/ormar/queryset/queries/query.py @@ -75,8 +75,8 @@ def apply_order_bys_for_primary_model(self) -> None: # noqa: CCR001 def _apply_default_model_sorting(self) -> None: """ - Applies orders_by from model Meta class (if provided), if it was not provided - it was filled by metaclass so it's always there and falls back to pk column + Applies orders_by from model OrmarConfig (if provided), if it was not provided + it was filled by metaclass, so it's always there and falls back to pk column """ for order_by in self.model_cls.ormar_config.orders_by: clause = ormar.OrderAction(order_str=order_by, model_cls=self.model_cls) diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index 257415c1b..14270c65d 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -84,12 +84,12 @@ def __init__( # noqa CFQ002 self.limit_sql_raw = limit_raw_sql @property - def model_meta(self) -> "OrmarConfig": + def model_config(self) -> "OrmarConfig": """ - Shortcut to model class Meta set on QuerySet model. + Shortcut to model class OrmarConfig set on QuerySet model. - :return: Meta class of the model - :rtype: model Meta class + :return: OrmarConfig of the model + :rtype: model's OrmarConfig """ if not self.model_cls: # pragma nocover raise ValueError("Model class of QuerySet is not initialized") @@ -247,22 +247,22 @@ def check_single_result_rows_count(rows: Sequence[Optional["T"]]) -> None: @property def database(self) -> databases.Database: """ - Shortcut to models database from Meta class. + Shortcut to models database from OrmarConfig class. :return: database :rtype: databases.Database """ - return self.model_meta.database + return self.model_config.database @property def table(self) -> sqlalchemy.Table: """ - Shortcut to models table from Meta class. + Shortcut to models table from OrmarConfig. :return: database table :rtype: sqlalchemy.Table """ - return self.model_meta.table + return self.model_config.table def build_select_expression( self, @@ -707,7 +707,7 @@ async def count(self, distinct: bool = True) -> int: expr = self.build_select_expression().alias("subquery_for_count") expr = sqlalchemy.func.count().select().select_from(expr) if distinct: - pk_column_name = self.model.get_column_alias(self.model_meta.pkname) + pk_column_name = self.model.get_column_alias(self.model_config.pkname) expr_distinct = expr.group_by(pk_column_name).alias("subquery_for_group") expr = sqlalchemy.func.count().select().select_from(expr_distinct) return await self.database.fetch_val(expr) @@ -1036,7 +1036,7 @@ async def update_or_create(self, **kwargs: Any) -> "T": :return: updated or created model :rtype: Model """ - pk_name = self.model_meta.pkname + pk_name = self.model_config.pkname if "pk" in kwargs: kwargs[pk_name] = kwargs.pop("pk") if pk_name not in kwargs or kwargs.get(pk_name) is None: @@ -1102,7 +1102,7 @@ async def iterate( # noqa: A003 rows: list = [] last_primary_key = None - pk_alias = self.model.get_column_alias(self.model_meta.pkname) + pk_alias = self.model.get_column_alias(self.model_config.pkname) async for row in self.database.iterate(query=expr): current_primary_key = row[pk_alias] @@ -1188,7 +1188,7 @@ async def bulk_update( # noqa: CCR001 raise ModelListEmptyError("Bulk update objects are empty!") ready_objects = [] - pk_name = self.model_meta.pkname + pk_name = self.model_config.pkname if not columns: columns = list( self.model.extract_db_own_fields().union( @@ -1214,9 +1214,9 @@ async def bulk_update( # noqa: CCR001 ) await asyncio.sleep(0) - pk_column = self.model_meta.table.c.get(self.model.get_column_alias(pk_name)) + pk_column = self.model_config.table.c.get(self.model.get_column_alias(pk_name)) pk_column_name = self.model.get_column_alias(pk_name) - table_columns = [c.name for c in self.model_meta.table.c] + table_columns = [c.name for c in self.model_config.table.c] expr = self.table.update().where( pk_column == bindparam("new_" + pk_column_name) ) diff --git a/ormar/relations/querysetproxy.py b/ormar/relations/querysetproxy.py index 7fd3d658d..83a4b0b5c 100644 --- a/ormar/relations/querysetproxy.py +++ b/ormar/relations/querysetproxy.py @@ -554,7 +554,7 @@ async def update_or_create(self, **kwargs: Any) -> "T": :return: updated or created model :rtype: Model """ - pk_name = self.queryset.model_meta.pkname + pk_name = self.queryset.model_config.pkname if "pk" in kwargs: kwargs[pk_name] = kwargs.pop("pk") if pk_name not in kwargs or kwargs.get(pk_name) is None: diff --git a/ormar/signals/__init__.py b/ormar/signals/__init__.py index 86da0ba9a..74a642cc6 100644 --- a/ormar/signals/__init__.py +++ b/ormar/signals/__init__.py @@ -1,5 +1,5 @@ """ -Signals and SignalEmitter that gathers the signals on models Meta. +Signals and SignalEmitter that gathers the signals on models OrmarConfig. Used to signal receivers functions about events, i.e. post_save, pre_delete etc. """ diff --git a/tests/test_relations/test_customizing_through_model_relation_names.py b/tests/test_relations/test_customizing_through_model_relation_names.py index 1aa3630cc..d75290623 100644 --- a/tests/test_relations/test_customizing_through_model_relation_names.py +++ b/tests/test_relations/test_customizing_through_model_relation_names.py @@ -30,11 +30,11 @@ class Student(ormar.Model): def test_tables_columns(): - through_meta = Student.ormar_config.model_fields["courses"].through.ormar_config - assert "course_id" in through_meta.table.c - assert "student_id" in through_meta.table.c - assert "course_id" in through_meta.model_fields - assert "student_id" in through_meta.model_fields + through_config = Student.ormar_config.model_fields["courses"].through.ormar_config + assert "course_id" in through_config.table.c + assert "student_id" in through_config.table.c + assert "course_id" in through_config.model_fields + assert "student_id" in through_config.model_fields @pytest.mark.asyncio From ac00c7818b18e591f5b6cad85e8f73a74dfc8219 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 18 Feb 2024 21:03:19 +0100 Subject: [PATCH 81/95] filter out pydantic serializer warnings --- ormar/models/helpers/relations.py | 21 ++++++++++++++------- ormar/models/metaclass.py | 7 ++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/ormar/models/helpers/relations.py b/ormar/models/helpers/relations.py index 4704f11d8..823efc63a 100644 --- a/ormar/models/helpers/relations.py +++ b/ormar/models/helpers/relations.py @@ -1,10 +1,13 @@ import inspect +import warnings from typing import TYPE_CHECKING, Any, List, Optional, Type, Union, cast from pydantic import BaseModel, create_model, field_serializer from pydantic._internal._decorators import DecoratorInfos from pydantic.fields import FieldInfo -from pydantic_core.core_schema import SerializerFunctionWrapHandler +from pydantic_core.core_schema import ( + SerializerFunctionWrapHandler, +) import ormar from ormar import ForeignKey, ManyToMany @@ -149,14 +152,14 @@ def register_reverse_model_fields(model_field: "ForeignKeyField") -> None: annotation=field_type, default=None ) add_field_serializer_for_reverse_relations( - to_model=model_field.to, related_name=related_name, field_type=field_type + to_model=model_field.to, related_name=related_name ) model_field.to.model_rebuild(force=True) setattr(model_field.to, related_name, RelationDescriptor(name=related_name)) def add_field_serializer_for_reverse_relations( - to_model: Type["Model"], related_name: str, field_type: type + to_model: Type["Model"], related_name: str ) -> None: def serialize( self: "Model", children: List["Model"], handler: SerializerFunctionWrapHandler @@ -166,7 +169,11 @@ def serialize( by excluding the children. """ try: - return handler(children) + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", message="Pydantic serializer warnings" + ) + return handler(children) except ValueError as exc: if not str(exc).startswith("Circular reference"): # pragma: no cover raise exc @@ -177,9 +184,9 @@ def serialize( result.append({child.ormar_config.pkname: child.pk}) return result - decorator = field_serializer( - related_name, mode="wrap", check_fields=False, return_type=field_type - )(serialize) + decorator = field_serializer(related_name, mode="wrap", check_fields=False)( + serialize + ) setattr(to_model, f"serialize_{related_name}", decorator) DecoratorInfos.build(to_model) diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 348098e0d..0d19db475 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -1,5 +1,6 @@ import copy import sys +import warnings from pathlib import Path from typing import ( TYPE_CHECKING, @@ -560,7 +561,11 @@ def serialize( Serialize a value if it's not expired weak reference. """ try: - return handler(value) + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", message="Pydantic serializer warnings" + ) + return handler(value) except ReferenceError: return None except ValueError as exc: From 2d798666c01a52012a1d6d754e5ae2b89acefb8f Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 18 Feb 2024 21:49:49 +0100 Subject: [PATCH 82/95] remove choices leftovers --- docs_src/models/docs005.py | 3 --- docs_src/queries/docs002.py | 1 - docs_src/queries/docs003.py | 1 - docs_src/queries/docs005.py | 1 - ormar/fields/base.py | 3 +-- ormar/fields/parsers.py | 4 ++-- ormar/models/helpers/validation.py | 9 +++------ ormar/models/mixins/save_mixin.py | 2 +- ormar/models/quick_access_views.py | 1 - ormar/queryset/queryset.py | 2 +- tests/test_model_definition/test_models.py | 11 +++++------ tests/test_queries/test_queryset_level_methods.py | 1 - tests/test_relations/test_foreign_keys.py | 2 +- .../test_postgress_select_related_with_limit.py | 4 +--- 14 files changed, 15 insertions(+), 30 deletions(-) diff --git a/docs_src/models/docs005.py b/docs_src/models/docs005.py index a95d477d5..0d309eb5e 100644 --- a/docs_src/models/docs005.py +++ b/docs_src/models/docs005.py @@ -36,7 +36,6 @@ class Course(ormar.Model): 'sql_nullable': False, 'index': False, 'unique': False, - 'choices': False, 'virtual': None, 'is_multi': None, 'is_relation': None, @@ -79,7 +78,6 @@ class Course(ormar.Model): 'sql_nullable': False, 'index': False, 'unique': False, - 'choices': False, 'virtual': None, 'is_multi': None, 'is_relation': None, @@ -120,7 +118,6 @@ class Course(ormar.Model): 'sql_nullable': True, 'index': False, 'unique': False, - 'choices': False, 'virtual': None, 'is_multi': None, 'is_relation': None, diff --git a/docs_src/queries/docs002.py b/docs_src/queries/docs002.py index 55117053b..1c3306819 100644 --- a/docs_src/queries/docs002.py +++ b/docs_src/queries/docs002.py @@ -23,7 +23,6 @@ class Book(ormar.Model): genre: str = ormar.String( max_length=100, default="Fiction", - choices=["Fiction", "Adventure", "Historic", "Fantasy"], ) diff --git a/docs_src/queries/docs003.py b/docs_src/queries/docs003.py index a0f310a71..09b928e75 100644 --- a/docs_src/queries/docs003.py +++ b/docs_src/queries/docs003.py @@ -21,7 +21,6 @@ class Book(ormar.Model): genre: str = ormar.String( max_length=100, default="Fiction", - choices=["Fiction", "Adventure", "Historic", "Fantasy"], ) diff --git a/docs_src/queries/docs005.py b/docs_src/queries/docs005.py index 3145b9216..ff9a3606f 100644 --- a/docs_src/queries/docs005.py +++ b/docs_src/queries/docs005.py @@ -21,7 +21,6 @@ class Book(ormar.Model): genre: str = ormar.String( max_length=100, default="Fiction", - choices=["Fiction", "Adventure", "Historic", "Fantasy"], ) diff --git a/ormar/fields/base.py b/ormar/fields/base.py index 297f83abd..a55f9a956 100644 --- a/ormar/fields/base.py +++ b/ormar/fields/base.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Type, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union import sqlalchemy from pydantic.fields import FieldInfo, _Unset @@ -43,7 +43,6 @@ def __init__(self, **kwargs: Any) -> None: self.sql_nullable: bool = kwargs.pop("sql_nullable", False) self.index: bool = kwargs.pop("index", False) self.unique: bool = kwargs.pop("unique", False) - self.choices: Sequence = kwargs.pop("choices", False) self.virtual: bool = kwargs.pop( "virtual", None diff --git a/ormar/fields/parsers.py b/ormar/fields/parsers.py index 4e29686e2..9b73304fc 100644 --- a/ormar/fields/parsers.py +++ b/ormar/fields/parsers.py @@ -53,10 +53,10 @@ def encode_json(value: Any) -> Optional[str]: def re_dump_value(value: str) -> Union[str, bytes]: """ - Rw-dumps choices due to different string representation in orjson and json + Re-dumps value due to different string representation in orjson and json :param value: string to re-dump :type value: str - :return: re-dumped choices + :return: re-dumped value :rtype: List[str] """ try: diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index 73e49d839..f284ce8b9 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -201,7 +201,7 @@ def overwrite_binary_format(schema: Dict[str, Any], model: Type["Model"]) -> Non prop["format"] = "base64" -def construct_schema_function_without_choices() -> Callable: +def construct_schema_function() -> Callable: """ Modifies model example and description if needed. @@ -221,13 +221,10 @@ def schema_extra(schema: Dict[str, Any], model: Type["Model"]) -> None: def modify_schema_example(model: Type["Model"]) -> None: # noqa CCR001 """ - Checks if Model has any fields with choices set. - If yes it adds choices validation into pre root validators. + Modifies the schema example in openapi schema. :param model: newly constructed Model :type model: Model class """ if not config_field_not_set(model=model, field_name="model_fields"): - model.model_config["json_schema_extra"] = ( - construct_schema_function_without_choices() - ) + model.model_config["json_schema_extra"] = construct_schema_function() diff --git a/ormar/models/mixins/save_mixin.py b/ormar/models/mixins/save_mixin.py index 25e87c2d2..e75949929 100644 --- a/ormar/models/mixins/save_mixin.py +++ b/ormar/models/mixins/save_mixin.py @@ -238,7 +238,7 @@ def populate_default_values(cls, new_kwargs: Dict) -> Dict: return new_kwargs @classmethod - def validate_choices(cls, new_kwargs: Dict) -> Dict: + def validate_enums(cls, new_kwargs: Dict) -> Dict: """ Receives dictionary of model that is about to be saved and validates the fields with choices set to see if the value is allowed. diff --git a/ormar/models/quick_access_views.py b/ormar/models/quick_access_views.py index a44c08f08..17cadb778 100644 --- a/ormar/models/quick_access_views.py +++ b/ormar/models/quick_access_views.py @@ -21,7 +21,6 @@ "__private_attributes__", "__same__", "_calculate_keys", - "_choices_fields", "_convert_json", "_extract_db_related_names", "_extract_model_db_fields", diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index 14270c65d..84657fe84 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -801,7 +801,7 @@ async def update(self, each: bool = False, **kwargs: Any) -> int: self.model.extract_related_names() ) updates = {k: v for k, v in kwargs.items() if k in self_fields} - updates = self.model.validate_choices(updates) + updates = self.model.validate_enums(updates) updates = self.model.translate_columns_to_aliases(updates) expr = FilterQuery(filter_clauses=self.filter_clauses).apply( diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index 452696e36..df35bff27 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -44,7 +44,7 @@ class LargeBinaryStr(ormar.Model): id: int = ormar.Integer(primary_key=True) test_binary: str = ormar.LargeBinary( - max_length=100000, choices=[blob3, blob4], represent_as_base64_str=True + max_length=100000, represent_as_base64_str=True ) @@ -54,7 +54,6 @@ class LargeBinaryNullableStr(ormar.Model): id: int = ormar.Integer(primary_key=True) test_binary: str = ormar.LargeBinary( max_length=100000, - choices=[blob3, blob4], represent_as_base64_str=True, nullable=True, ) @@ -466,9 +465,9 @@ async def test_model_first(): @pytest.mark.asyncio async def test_model_choices(): - """Test that choices work properly for various types of fields.""" + """Test that enum work properly for various types of fields.""" async with base_ormar_config.database: - # Test valid choices. + # Test valid enums values. await asyncio.gather( Country.objects.create(name="Canada", taxed=True, country_code=1), Country.objects.create(name="Algeria", taxed=True, country_code=213), @@ -505,8 +504,8 @@ async def test_model_choices(): @pytest.mark.asyncio -async def test_nullable_field_model_choices(): - """Test that choices work properly for according to nullable setting""" +async def test_nullable_field_model_enum(): + """Test that enum work properly for according to nullable setting""" async with base_ormar_config.database: c1 = await NullableCountry(name=None).save() assert c1.name is None diff --git a/tests/test_queries/test_queryset_level_methods.py b/tests/test_queries/test_queryset_level_methods.py index f223eb221..801b028f0 100644 --- a/tests/test_queries/test_queryset_level_methods.py +++ b/tests/test_queries/test_queryset_level_methods.py @@ -32,7 +32,6 @@ class Book(ormar.Model): genre: str = ormar.String( max_length=100, default="Fiction", - choices=["Fiction", "Adventure", "Historic", "Fantasy"], ) diff --git a/tests/test_relations/test_foreign_keys.py b/tests/test_relations/test_foreign_keys.py index e77d9a1f1..49c1ae5b6 100644 --- a/tests/test_relations/test_foreign_keys.py +++ b/tests/test_relations/test_foreign_keys.py @@ -41,7 +41,7 @@ class Organisation(ormar.Model): ormar_config = base_ormar_config.copy(tablename="org") id: int = ormar.Integer(primary_key=True) - ident: str = ormar.String(max_length=100, choices=["ACME Ltd", "Other ltd"]) + ident: str = ormar.String(max_length=100) class Team(ormar.Model): diff --git a/tests/test_relations/test_postgress_select_related_with_limit.py b/tests/test_relations/test_postgress_select_related_with_limit.py index a12d5b009..14ff84964 100644 --- a/tests/test_relations/test_postgress_select_related_with_limit.py +++ b/tests/test_relations/test_postgress_select_related_with_limit.py @@ -27,9 +27,7 @@ class User(PrimaryKeyMixin, ormar.Model): mobile: str = ormar.String(unique=True, index=True, max_length=10) password: str = ormar.String(max_length=128) - level: str = ormar.String( - max_length=1, choices=list(Level), default=Level.STAFF.value - ) + level: Level = ormar.Enum(default=Level.STAFF, enum_class=Level) email: Optional[str] = ormar.String(max_length=255, nullable=True, default=None) avatar: Optional[str] = ormar.String(max_length=255, nullable=True, default=None) fullname: Optional[str] = ormar.String(max_length=64, nullable=True, default=None) From e7d1bdb6b5fcf6dc6142242f64c342f19af7bfa9 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 25 Feb 2024 19:03:24 +0100 Subject: [PATCH 83/95] remove leftovers after property_fields, keep only enough to exclude them in initialization --- ormar/exceptions.py | 1 - ormar/models/descriptors/__init__.py | 2 -- ormar/models/descriptors/descriptors.py | 22 ----------------- ormar/models/metaclass.py | 15 +++--------- ormar/models/newbasemodel.py | 32 ------------------------- 5 files changed, 3 insertions(+), 69 deletions(-) diff --git a/ormar/exceptions.py b/ormar/exceptions.py index 47172000b..d7e56d1fc 100644 --- a/ormar/exceptions.py +++ b/ormar/exceptions.py @@ -15,7 +15,6 @@ class ModelDefinitionError(AsyncOrmException): """ Raised for errors related to the model definition itself: - * setting @property_field on method with arguments other than func(self) * defining a Field without required parameters * defining a model with more than one primary_key * defining a model without primary_key diff --git a/ormar/models/descriptors/__init__.py b/ormar/models/descriptors/__init__.py index 459e48db6..58e29e9ab 100644 --- a/ormar/models/descriptors/__init__.py +++ b/ormar/models/descriptors/__init__.py @@ -2,7 +2,6 @@ BytesDescriptor, JsonDescriptor, PkDescriptor, - PropertyDescriptor, PydanticDescriptor, RelationDescriptor, ) @@ -10,7 +9,6 @@ __all__ = [ "PydanticDescriptor", "RelationDescriptor", - "PropertyDescriptor", "PkDescriptor", "JsonDescriptor", "BytesDescriptor", diff --git a/ormar/models/descriptors/descriptors.py b/ormar/models/descriptors/descriptors.py index 33e6a69da..40e96d72e 100644 --- a/ormar/models/descriptors/descriptors.py +++ b/ormar/models/descriptors/descriptors.py @@ -112,25 +112,3 @@ def __set__(self, instance: "Model", value: Any) -> None: if not isinstance(instance.__dict__.get(self.name), list): instance.set_save_status(False) - - -class PropertyDescriptor: - """ - Property descriptor handles methods decorated with @property_field decorator. - They are read only. - """ - - def __init__(self, name: str, function: Any) -> None: - self.name = name - self.function = function - - def __get__(self, instance: "Model", owner: Type["Model"]) -> Any: - if instance is None: - return self - if instance is not None and self.function is not None: - bound = self.function.__get__(instance, instance.__class__) - return bound() if callable(bound) else bound - - def __set__(self, instance: "Model", value: Any) -> None: # pragma: no cover - # kept here so it's a data-descriptor and precedes __dict__ lookup - pass diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index 0d19db475..64dfbeb12 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -35,7 +35,6 @@ from ormar.models.descriptors import ( JsonDescriptor, PkDescriptor, - PropertyDescriptor, PydanticDescriptor, RelationDescriptor, ) @@ -92,8 +91,8 @@ def add_cached_properties(new_model: Type["Model"]) -> None: def add_property_fields(new_model: Type["Model"], attrs: Dict) -> None: # noqa: CCR001 """ - Checks class namespace for properties or functions with __property_field__. - If attribute have __property_field__ it was decorated with @property_field. + Checks class namespace for properties or functions with computed_field. + If attribute have decorator_info it was decorated with @computed_field. Functions like this are exposed in dict() (therefore also fastapi result). Names of property fields are cached for quicker access / extraction. @@ -597,7 +596,7 @@ def __new__( # type: ignore # noqa: CCR001 updates class namespace. Extracts settings and fields from parent classes. - Fetches methods decorated with @property_field decorator + Fetches methods decorated with @computed_field decorator to expose them later in dict(). Construct parent pydantic Metaclass/ Model. @@ -682,14 +681,6 @@ def __new__( # type: ignore # noqa: CCR001 ) new_model.model_rebuild(force=True) - for item in new_model.ormar_config.property_fields: - function = getattr(new_model, item) - setattr( - new_model, - item, - PropertyDescriptor(name=item, function=function), - ) - new_model.pk = PkDescriptor(name=new_model.ormar_config.pkname) remove_excluded_parent_fields(new_model) diff --git a/ormar/models/newbasemodel.py b/ormar/models/newbasemodel.py index 41d180f25..3e269b932 100644 --- a/ormar/models/newbasemodel.py +++ b/ormar/models/newbasemodel.py @@ -482,32 +482,6 @@ def set_save_status(self, status: bool) -> None: """Sets value of the save status""" object.__setattr__(self, "_orm_saved", status) - @classmethod - def get_properties( - cls, include: Union[Set, Dict, None], exclude: Union[Set, Dict, None] - ) -> Set[str]: - """ - Returns a set of names of functions/fields decorated with - @property_field decorator. - - They are added to dictionary when called directly and therefore also are - present in fastapi responses. - - :param include: fields to include - :type include: Union[Set, Dict, None] - :param exclude: fields to exclude - :type exclude: Union[Set, Dict, None] - :return: set of property fields names - :rtype: Set[str] - """ - - props = cls.ormar_config.property_fields - if include: - props = {prop for prop in props if prop in include} - if exclude: - props = {prop for prop in props if prop not in exclude} - return props - @classmethod def update_forward_refs(cls, **localns: Any) -> None: """ @@ -923,12 +897,6 @@ def model_dump( # type: ignore # noqa A003 exclude_list=exclude_list, ) - # include model properties as fields in dict - if object.__getattribute__(self, "ormar_config").property_fields: - props = self.get_properties(include=include_dict, exclude=exclude_dict) - if props: - dict_instance.update({prop: getattr(self, prop) for prop in props}) - return dict_instance @typing_extensions.deprecated( From 1bbf90809f1489e6febc3ccf377dc6098a58cd88 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 25 Feb 2024 20:24:25 +0100 Subject: [PATCH 84/95] add migration guide --- docs/migration.md | 330 ++++++++++++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + ormar/warnings.py | 2 +- 3 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 docs/migration.md diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 000000000..2637ac9d7 --- /dev/null +++ b/docs/migration.md @@ -0,0 +1,330 @@ +# Migration to 0.20.0 based on pydantic 2.X.X + +Version 0.20.0 provides support for pydantic v2.X.X that provides significant speed boost (validation and serialization is written in rust) and cleaner api for developers, +at the same time it drops support for pydantic v.1.X.X. There are changes in `ormar` interface corresponding to changes made in `pydantic`. + +## Breaking changes + +Migration to version >= 0.20.0 requires several changes in order to work properly. + +## `ormar` Model configuration + +Instead of defining a `Meta` class now each of the ormar models require an ormar_config parameter that is an instance of the `OrmarConfig` class. +Note that the attribute must be named `ormar_config` and be an instance of the config class. + +```python +import databases +import ormar +import sqlalchemy + +database = databases.Database("sqlite:///db.sqlite") +metadata = sqlalchemy.MetaData() + +# ormar < 0.20 +class Album(ormar.Model): + class Meta: + database = database + metadata = metadata + tablename = "albums" + + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + +# ormar >= 0.20 +class AlbumV20(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="albums_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) +``` + +### `OrmarConfig` api/ parameters + +The `ormar_config` expose the same set of settings as `Meta` class used to provide. +That means that you can use any of the following parameters initializing the config: + +```python +metadata: Optional[sqlalchemy.MetaData] +database: Optional[databases.Database] +engine: Optional[sqlalchemy.engine.Engine] +tablename: Optional[str] +order_by: Optional[List[str]] +abstract: bool +exclude_parent_fields: Optional[List[str]] +queryset_class: Type[QuerySet] +extra: Extra +constraints: Optional[List[ColumnCollectionConstraint]] +``` + +### `BaseMeta` equivalent - best practice + +Note that to reduce the duplication of code and ease of development it's still recommended to create a base config and provide each of the models with a copy. +OrmarConfig provides a convenient `copy` method for that purpose. + +The `copy` method accepts the same parameters as `OrmarConfig` init, so you can overwrite if needed, but by default it will return already existing attributes, except for: `tablename`, `order_by` and `constraints` which by default are cleared. + +```python hl_lines="5-8 11 20" +import databases +import ormar +import sqlalchemy + +base_ormar_config = ormar.OrmarConfig( + database=databases.Database("sqlite:///db.sqlite"), + metadata=sqlalchemy.MetaData() +) + +class AlbumV20(ormar.Model): + ormar_config = base_ormar_config.copy( + tablename="albums_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + + +class TrackV20(ormar.Model): + ormar_config = base_ormar_config.copy( + tablename="tracks_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) +``` + +## `choices` Field parameter is no longer supported. + +Before version 0.20 you could provide `choices` parameter to any existing ormar Field to limit the accepted values. +This functionality was dropped, and you should use `ormar.Enum` field that was designed for this purpose. +If you want to keep the database field type (i.e. an Integer field) you can always write a custom validator. + +```python +import databases +import ormar +import sqlalchemy + +database = databases.Database("sqlite:///db.sqlite") +metadata = sqlalchemy.MetaData() + +# ormar < 0.20 +class Artist(ormar.Model): + class Meta: + database = database + metadata = metadata + + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + country: str = ormar.String(default=False, max_length=50, choices=["UK", "US", "Vietnam", "Colombia"]) + +# ormar >= 0.20 +from enum import Enum + +class Country(str, Enum): + UK = "UK" + US = "US" + VIETNAM = "Vietnam" + COLOMBIA = "Colombia" + +class ArtistV20(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="artists_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + country: Country = ormar.Enum(enum_class=Country) +``` + + +## `pydantic_only` Field parameter is no longer supported + +`pydantic_only` fields were already deprecated and are removed in v 0.20. Ormar allows defining pydantic fields as in ordinary pydantic model. + +```python +import databases +import ormar +import sqlalchemy + +database = databases.Database("sqlite:///db.sqlite") +metadata = sqlalchemy.MetaData() + +# ormar < 0.20 +class Dish(ormar.Model): + class Meta: + database = database + metadata = metadata + tablename = "dishes" + + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + cook: str = ormar.String(max_length=40, pydantic_only=True, default="sam") + +# ormar >= 0.20 +class DishV20(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="dishes_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + cook: str = "sam" # this is normal pydantic field +``` + +## `property_field` decorator is no longer supported + +`property_field` decorator was used to provide a way to pass calculated fields that were included in dictionary/ serialized json representation of the model. +Version 2.X of pydantic introduced such a possibility, so you should now switch to the one native to the pydantic. + +```python +import databases +import ormar +import sqlalchemy +import pydantic + +database = databases.Database("sqlite:///db.sqlite") +metadata = sqlalchemy.MetaData() + +# ormar < 0.20 +class Employee(ormar.Model): + class Meta: + database = database + metadata = metadata + + + id: int = ormar.Integer(primary_key=True) + first_name: str = ormar.String(max_length=100) + last_name: str = ormar.String(max_length=100) + + @ormar.property_field() + def full_name(self) -> str: + return f"{self.first_name} {self.last_name}" + +# ormar >= 0.20 +class EmployeeV20(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) + + id: int = ormar.Integer(primary_key=True) + first_name: str = ormar.String(max_length=100) + last_name: str = ormar.String(max_length=100) + + @pydantic.computed_field() + def full_name(self) -> str: + return f"{self.first_name} {self.last_name}" +``` + +## Deprecated methods + +All methods listed below are deprecated and will be removed in version 0.30 of `ormar`. + +### `dict()` becomes the `model_dump()` + +```python +import databases +import ormar +import sqlalchemy + +database = databases.Database("sqlite:///db.sqlite") +metadata = sqlalchemy.MetaData() + +class Album(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="albums" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + +album = Album(name="Dark Side of the Moon") + +# ormar < 0.20 +album_dict = album.dict() + +# ormar >= 0.20 +new_album_dict = album.model_dump() +``` + +Note that parameters remain the same i.e. `include`, `exclude` etc. + +### `json()` becomes the `model_dump_json()` + +```python +import databases +import ormar +import sqlalchemy + +database = databases.Database("sqlite:///db.sqlite") +metadata = sqlalchemy.MetaData() + +class Album(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="albums" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + +album = Album(name="Dark Side of the Moon") + +# ormar < 0.20 +album_json= album.json() + +# ormar >= 0.20 +new_album_dict = album.model_dump_json() +``` + +Note that parameters remain the same i.e. `include`, `exclude` etc. + +### `construct()` becomes the `model_construct()` + +```python +import databases +import ormar +import sqlalchemy + +database = databases.Database("sqlite:///db.sqlite") +metadata = sqlalchemy.MetaData() + +class Album(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="albums" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + +params = { + "name": "Dark Side of the Moon", + "favorite": True, +} +# ormar < 0.20 +album = Album.construct(**params) + +# ormar >= 0.20 +album = Album.model_construct(**params) +``` + +To read more about construct please refer to `pydantic` documentation. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 2c1e97255..cd9cc6721 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -39,6 +39,7 @@ nav: - Using ormar in responses: fastapi/response.md - Using ormar in requests: fastapi/requests.md - Use with mypy: mypy.md + - Migration to v 0.20: migration.md - PyCharm plugin: plugin.md - Contributing: contributing.md - Release Notes: releases.md diff --git a/ormar/warnings.py b/ormar/warnings.py index 55fcba4bf..318fd3c16 100644 --- a/ormar/warnings.py +++ b/ormar/warnings.py @@ -39,7 +39,7 @@ def __str__(self) -> str: # pragma: no cover f" to be removed in V{self.expected_removal[0]}.{self.expected_removal[1]}." ) if self.since == (0, 20): - message += " See Ormar V0.20 Migration Guide at https://collerek.github.io/ormar/migration-to-v0.20/" + message += " See Ormar V0.20 Migration Guide at https://collerek.github.io/ormar/migration/" return message From c8dc612dfb9abe1431a8a1a5019567fb533ca6e4 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 10 Mar 2024 15:48:25 +0100 Subject: [PATCH 85/95] fix meta references --- ormar/queryset/actions/order_action.py | 2 +- ormar/queryset/join.py | 4 +- .../test_field_quoting.py | 43 ++++++------------- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/ormar/queryset/actions/order_action.py b/ormar/queryset/actions/order_action.py index 08c602846..a77563c36 100644 --- a/ormar/queryset/actions/order_action.py +++ b/ormar/queryset/actions/order_action.py @@ -80,7 +80,7 @@ def get_text_clause(self) -> sqlalchemy.sql.expression.TextClause: :return: complied and escaped clause :rtype: sqlalchemy.sql.elements.TextClause """ - dialect = self.target_model.Meta.database._backend._dialect + dialect = self.target_model.ormar_config.database._backend._dialect quoter = dialect.identifier_preparer.quote prefix = f"{self.table_prefix}_" if self.table_prefix else "" table_name = self.table.name diff --git a/ormar/queryset/join.py b/ormar/queryset/join.py index 7184b8ae0..9d7e4d157 100644 --- a/ormar/queryset/join.py +++ b/ormar/queryset/join.py @@ -119,7 +119,7 @@ def _on_clause( :return: clause combining all strings :rtype: sqlalchemy.text """ - dialect = self.main_model.Meta.database._backend._dialect + dialect = self.main_model.ormar_config.database._backend._dialect quoter = dialect.identifier_preparer.quote left_part = ( f"{quoter(f'{self.next_alias}_{to_table_name}')}.{quoter(to_column_name)}" @@ -296,7 +296,7 @@ def _process_join(self) -> None: # noqa: CFQ002 on_clause = self._on_clause( previous_alias=self.own_alias, - from_table_name=self.target_field.owner.Meta.tablename, + from_table_name=self.target_field.owner.ormar_config.tablename, from_column_name=from_key, to_table_name=self.to_table.name, to_column_name=to_key, diff --git a/tests/test_model_definition/test_field_quoting.py b/tests/test_model_definition/test_field_quoting.py index 5bc766798..c903334fb 100644 --- a/tests/test_model_definition/test_field_quoting.py +++ b/tests/test_model_definition/test_field_quoting.py @@ -1,41 +1,30 @@ from typing import Optional -import databases import ormar import pytest -import sqlalchemy -from tests.settings import DATABASE_URL +from tests.lifespan import init_tests +from tests.settings import create_config -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() +base_ormar_config = create_config(force_rollback=True) class SchoolClass(ormar.Model): - class Meta: - tablename = "app.schoolclasses" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="app.schoolclasses") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Category(ormar.Model): - class Meta: - tablename = "app.categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="app.categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Student(ormar.Model): - class Meta: - tablename = "app.students" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="app.students") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -48,13 +37,7 @@ class Meta: ) -@pytest.fixture(autouse=True, scope="module") -def create_test_database(): - engine = sqlalchemy.create_engine(DATABASE_URL) - metadata.drop_all(engine) - metadata.create_all(engine) - yield - metadata.drop_all(engine) +create_test_database = init_tests(base_ormar_config) async def create_data(): @@ -75,8 +58,8 @@ async def create_data(): @pytest.mark.asyncio async def test_quotes_left_join(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await create_data() students = await Student.objects.filter( (Student.schoolclass.name == "Math") @@ -91,8 +74,8 @@ async def test_quotes_left_join(): @pytest.mark.asyncio async def test_quotes_reverse_join(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await create_data() schoolclasses = await SchoolClass.objects.filter(students__gpa__gt=3).all() for schoolclass in schoolclasses: @@ -102,8 +85,8 @@ async def test_quotes_reverse_join(): @pytest.mark.asyncio async def test_quotes_deep_join(): - async with database: - async with database.transaction(force_rollback=True): + async with base_ormar_config.database: + async with base_ormar_config.database.transaction(force_rollback=True): await create_data() schoolclasses = await SchoolClass.objects.filter( students__category__name="Domestic" From 4b0a5011652eec2de173e006b93d48d7cb0f0ac0 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 10 Mar 2024 16:04:29 +0100 Subject: [PATCH 86/95] downgrade databases for now --- poetry.lock | 8 ++++---- pyproject.toml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index f32d4b5b4..657c01f6d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -614,14 +614,14 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "databases" -version = "0.8.0" +version = "0.7.0" description = "Async database support for Python." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "databases-0.8.0-py3-none-any.whl", hash = "sha256:0ceb7fd5c740d846e1f4f58c0256d780a6786841ec8e624a21f1eb1b51a9093d"}, - {file = "databases-0.8.0.tar.gz", hash = "sha256:6544d82e9926f233d694ec29cd018403444c7fb6e863af881a8304d1ff5cfb90"}, + {file = "databases-0.7.0-py3-none-any.whl", hash = "sha256:cf5da4b8a3e3cd038c459529725ebb64931cbbb7a091102664f20ef8f6cefd0d"}, + {file = "databases-0.7.0.tar.gz", hash = "sha256:ea2d419d3d2eb80595b7ceb8f282056f080af62efe2fb9bcd83562f93ec4b674"}, ] [package.dependencies] @@ -2691,4 +2691,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "07f42e04f1a0a496c83a81dcbe310c1b800e14d46c58e3da08a8a7347e5d6551" +content-hash = "3b912bdff99c92f4e359315eb4a0a4107e4dc9c5484ba30bd0cea0e10746001b" diff --git a/pyproject.toml b/pyproject.toml index e23b6a98a..a707a696f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,9 +42,9 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.8.0" -databases = "^0.8.0" +databases = "^0.7.0" pydantic = "v2.5.3" -SQLAlchemy = "^1.4.48" +SQLAlchemy = "^1.4.42" cryptography = { version = "^41.0.3", optional = true } # Async database drivers aiosqlite = { version = "^0.19.0", optional = true } From 27a981c1c26dc8395f8f561c364a1b02b76fd626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Goran=20Meki=C4=87?= Date: Sun, 10 Mar 2024 16:18:53 +0100 Subject: [PATCH 87/95] Change line numbers in documentation (#1265) --- README.md | 33 ++--- docs/fastapi/index.md | 19 +-- docs/fastapi/requests.md | 10 +- docs/fastapi/response.md | 23 +-- docs/fields/common-parameters.md | 13 +- docs/fields/encryption.md | 21 +-- docs/fields/field-types.md | 18 ++- docs/fields/pydantic-fields.md | 52 +++---- docs/index.md | 48 +++--- docs/models/index.md | 136 ++++++++--------- docs/models/inheritance.md | 164 +++++++++------------ docs/models/internals.md | 10 +- docs/models/methods.md | 78 +++------- docs/models/migrations.md | 4 +- docs/queries/aggregations.md | 10 +- docs/queries/create.md | 14 +- docs/queries/delete.md | 24 +-- docs/queries/filter-and-sort.md | 43 ++---- docs/queries/joins-and-subqueries.md | 80 +++------- docs/queries/pagination-and-rows-number.md | 15 +- docs/queries/raw-data.md | 21 +-- docs/queries/read.md | 30 +--- docs/queries/select-columns.md | 26 +--- docs/queries/update.md | 6 +- docs/relations/foreign-key.md | 22 ++- docs/relations/index.md | 74 +++++----- docs/relations/many-to-many.md | 42 +++--- docs/relations/postponed-annotations.md | 31 +--- docs/relations/queryset-proxy.md | 4 +- docs/signals.md | 44 +++--- docs/transactions.md | 21 +-- docs_src/signals/docs002.py | 3 +- examples/script_from_readme.py | 21 ++- 33 files changed, 460 insertions(+), 700 deletions(-) diff --git a/README.md b/README.md index eb3705702..34c63b5e8 100644 --- a/README.md +++ b/README.md @@ -171,39 +171,31 @@ import ormar import sqlalchemy DATABASE_URL = "sqlite:///db.sqlite" -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - - -# note that this step is optional -> all ormar cares is a internal -# class with name Meta and proper parameters, but this way you do not -# have to repeat the same parameters if you use only one database -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + engine=sqlalchemy.create_engine(DATABASE_URL), +) # Note that all type hints are optional # below is a perfectly valid model declaration # class Author(ormar.Model): -# class Meta(BaseMeta): -# tablename = "authors" +# ormar_config = base_ormar_config.copy(tablename="authors") # # id = ormar.Integer(primary_key=True) # <= notice no field types # name = ormar.String(max_length=100) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -214,10 +206,9 @@ class Book(ormar.Model): # create the database # note that in production you should use migrations # note that this is not required if you connect to existing database -engine = sqlalchemy.create_engine(DATABASE_URL) # just to be sure we clear the db before -metadata.drop_all(engine) -metadata.create_all(engine) +base_ormar_config.metadata.drop_all(base_ormar_config.engine) +base_ormar_config.metadata.create_all(base_ormar_config.engine) # all functions below are divided into functionality categories @@ -546,7 +537,7 @@ async def raw_data(): async def with_connect(function): # note that for any other backend than sqlite you actually need to # connect to the database to perform db operations - async with database: + async with base_ormar_config.database: await function() # note that if you use framework like `fastapi` you shouldn't connect @@ -576,7 +567,7 @@ for func in [ asyncio.run(with_connect(func)) # drop the database tables -metadata.drop_all(engine) +base_ormar_config.metadata.drop_all(base_ormar_config.engine) ``` ## Ormar Specification diff --git a/docs/fastapi/index.md b/docs/fastapi/index.md index 25521a73c..4807a0c18 100644 --- a/docs/fastapi/index.md +++ b/docs/fastapi/index.md @@ -45,13 +45,10 @@ from fastapi import FastAPI async def lifespan(_: FastAPI) -> AsyncIterator[None]: if not config.database.is_connected: await config.database.connect() - config.metadata.drop_all(config.engine) - config.metadata.create_all(config.engine) yield if config.database.is_connected: - config.metadata.drop_all(config.engine) await config.database.disconnect() @@ -72,21 +69,21 @@ Define ormar models with appropriate fields. Those models will be used instead of pydantic ones. ```python +base_ormar_config = OrmarConfig( + metadata = metadata + database = database +) + + class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs/fastapi/requests.md b/docs/fastapi/requests.md index b2a5e829e..181b715f5 100644 --- a/docs/fastapi/requests.md +++ b/docs/fastapi/requests.md @@ -23,11 +23,13 @@ Field is not required if (any/many/all) of following: Example: ```python +base_ormar_config = ormar.OrmarConfig( + metadata=metadata + database=database +) + class User(ormar.Model): - class Meta: - tablename: str = "users" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255) diff --git a/docs/fastapi/response.md b/docs/fastapi/response.md index 8b3f8e009..3949bfeb9 100644 --- a/docs/fastapi/response.md +++ b/docs/fastapi/response.md @@ -22,11 +22,13 @@ Field is not required if (any/many/all) of following: Example: ```python +base_ormar_config = ormar.OrmarConfig( + metadata=metadata + database=database +) + class User(ormar.Model): - class Meta: - tablename: str = "users" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255) @@ -111,13 +113,13 @@ One is a dictionary with nested fields that represents the model tree structure, Assume for a second that our user's category is a separate model: ```python -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + metadata=metadata + database=database +) class Category(ormar.Model): - class Meta(BaseMeta): - tablename: str = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255) @@ -125,8 +127,7 @@ class Category(ormar.Model): class User(ormar.Model): - class Meta(BaseMeta): - tablename: str = "users" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255) diff --git a/docs/fields/common-parameters.md b/docs/fields/common-parameters.md index bee0f4150..80800c191 100644 --- a/docs/fields/common-parameters.md +++ b/docs/fields/common-parameters.md @@ -108,7 +108,7 @@ Used in sql only. Sample usage: -```Python hl_lines="21-23" +```Python hl_lines="20-22" --8<-- "../docs_src/fields/docs004.py" ``` @@ -184,12 +184,15 @@ So it's on you as a user to provide a type that is valid in the context of given As it's easy to break functionality of ormar the `overwrite_pydantic_type` argument is not available on relation fields! ```python +base_ormar_config = ormar.OrmarConfig( + metadata=metadata + database=database +) + + # sample overwrites class OverwriteTest(ormar.Model): - class Meta: - tablename = "overwrites" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="overwrites") id: int = ormar.Integer(primary_key=True) my_int: str = ormar.Integer(overwrite_pydantic_type=PositiveInt) diff --git a/docs/fields/encryption.md b/docs/fields/encryption.md index 9cc06b05d..7fe5be968 100644 --- a/docs/fields/encryption.md +++ b/docs/fields/encryption.md @@ -17,10 +17,14 @@ well as both-way encryption/decryption (`FERNET` backend). To encrypt a field you need to pass at minimum `encrypt_secret` and `encrypt_backend` parameters. -```python hl_lines="7-8" +```python hl_lines="10-12" +base_ormar_config = ormar.OrmarConfig( + metadata=metadata + database=database +) + class Filter(ormar.Model): - class Meta(BaseMeta): - tablename = "filters" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, @@ -59,8 +63,7 @@ Note that since this backend never decrypt the stored value it's only applicable ```python class Hash(ormar.Model): - class Meta(BaseMeta): - tablename = "hashes" + ormar_config = base_ormar_config.copy(tablename="hashes") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=128, @@ -106,8 +109,7 @@ as the returned value is parsed to corresponding python type. ```python class Filter(ormar.Model): - class Meta(BaseMeta): - tablename = "filters" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, @@ -152,8 +154,7 @@ argument by `encrypt_custom_backend`. ```python class Filter(ormar.Model): - class Meta(BaseMeta): - tablename = "filters" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, @@ -161,4 +162,4 @@ class Filter(ormar.Model): encrypt_backend=ormar.EncryptBackends.CUSTOM, encrypt_custom_backend=DummyBackend ) -``` \ No newline at end of file +``` diff --git a/docs/fields/field-types.md b/docs/fields/field-types.md index 4bb25e4a9..4cafaf2c7 100644 --- a/docs/fields/field-types.md +++ b/docs/fields/field-types.md @@ -160,11 +160,16 @@ That way you can i.e. set the value by API, even if value is not `utf-8` compati ```python import base64 ... # other imports skipped for brevity + + +base_ormar_config = ormar.OrmarConfig( + metadata=metadata + database=database +) + + class LargeBinaryStr(ormar.Model): - class Meta: - tablename = "my_str_blobs" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="my_str_blobs") id: int = ormar.Integer(primary_key=True) test_binary: str = ormar.LargeBinary( @@ -233,10 +238,7 @@ class TestEnum(Enum): val2 = 'Val2' class TestModel(ormar.Model): - class Meta: - tablename = "org" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="org") id: int = ormar.Integer(primary_key=True) # pass list(Enum) to choices diff --git a/docs/fields/pydantic-fields.md b/docs/fields/pydantic-fields.md index 042bd3654..800e349ee 100644 --- a/docs/fields/pydantic-fields.md +++ b/docs/fields/pydantic-fields.md @@ -22,17 +22,14 @@ If you set a field as `Optional`, it defaults to `None` if not provided and that exactly what's going to happen during loading from database. ```python -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() +base_ormar_config = ormar.OrmarConfig( + metadata=sqlalchemy.MetaData(), + database=databases.Database(DATABASE_URL), +) -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - class ModelTest(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200) @@ -57,17 +54,14 @@ By setting a default value, this value will be set on initialization and databas Note that setting a default to `None` is the same as setting the field to `Optional`. ```python -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() +base_ormar_config = ormar.OrmarConfig( + metadata=sqlalchemy.MetaData(), + database=databases.Database(DATABASE_URL), +) -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - class ModelTest(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200) @@ -97,13 +91,12 @@ on initialization and each database load. from pydantic import Field, PaymentCardNumber # ... -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() +base_ormar_config = ormar.OrmarConfig( + metadata=sqlalchemy.MetaData(), + database=databases.Database(DATABASE_URL), +) -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database CARD_NUMBERS = [ "123456789007", @@ -119,8 +112,7 @@ def get_number(): class ModelTest2(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200) @@ -149,13 +141,12 @@ You can provide a value for the field in your `__init__()` method before calling from pydantic import BaseModel # ... -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() +base_ormar_config = ormar.OrmarConfig( + metadata=sqlalchemy.MetaData(), + database=databases.Database(DATABASE_URL), +) -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database class PydanticTest(BaseModel): aa: str @@ -163,8 +154,7 @@ class PydanticTest(BaseModel): class ModelTest3(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() # provide your custom init function def __init__(self, **kwargs): @@ -192,4 +182,4 @@ assert test_check.pydantic_test.aa == "random" ``` !!!warning - If you do not provide a value in one of the above ways `ValidationError` will be raised on load from database. \ No newline at end of file + If you do not provide a value in one of the above ways `ValidationError` will be raised on load from database. diff --git a/docs/index.md b/docs/index.md index bb75b91aa..88b27340d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -128,17 +128,20 @@ For tests and basic applications the `sqlalchemy` is more than enough: # 1. Imports import sqlalchemy import databases +import ormar # 2. Initialization DATABASE_URL = "sqlite:///db.sqlite" -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() +base_ormar_config = ormar.OrmarConfig( + metadata=sqlalchemy.MetaData(), + database=databases.Database(DATABASE_URL), + engine=sqlalchemy.create_engine(DATABASE_URL), +) # Define models here # 3. Database creation and tables creation -engine = sqlalchemy.create_engine(DATABASE_URL) -metadata.create_all(engine) +base_ormar_config.metadata.create_all(engine) ``` For a sample configuration of alembic and more information regarding migrations and @@ -175,45 +178,39 @@ Note that you can find the same script in examples folder on github. from typing import Optional import databases -import pydantic import ormar import sqlalchemy DATABASE_URL = "sqlite:///db.sqlite" -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - - -# note that this step is optional -> all ormar cares is a internal -# class with name Meta and proper parameters, but this way you do not -# have to repeat the same parameters if you use only one database -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - - +base_ormar_config = ormar.OrmarConfig( + metadata=sqlalchemy.MetaData(), + database=databases.Database(DATABASE_URL), + engine = sqlalchemy.create_engine(DATABASE_URL), +) + +# note that this step is optional -> all ormar cares is a field with name +# ormar_config # and proper parameters, but this way you do not have to repeat +# the same parameters if you use only one database +# # Note that all type hints are optional # below is a perfectly valid model declaration # class Author(ormar.Model): -# class Meta(BaseMeta): -# tablename = "authors" +# ormar_config = base_ormar_config.copy(tablename="authors") # # id = ormar.Integer(primary_key=True) # <= notice no field types # name = ormar.String(max_length=100) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy(tablename="authors") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy(tablename="books") id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -224,10 +221,9 @@ class Book(ormar.Model): # create the database # note that in production you should use migrations # note that this is not required if you connect to existing database -engine = sqlalchemy.create_engine(DATABASE_URL) # just to be sure we clear the db before -metadata.drop_all(engine) -metadata.create_all(engine) +base_ormar_config.metadata.drop_all(engine) +base_ormar_config.metadata.create_all(engine) # all functions below are divided into functionality categories diff --git a/docs/models/index.md b/docs/models/index.md index 4c3239350..05ebcdbb6 100644 --- a/docs/models/index.md +++ b/docs/models/index.md @@ -9,7 +9,7 @@ They are being managed in the background and you do not have to create them on y To build an ormar model you simply need to inherit a `ormar.Model` class. -```Python hl_lines="10" +```Python hl_lines="9" --8<-- "../docs_src/models/docs001.py" ``` @@ -23,7 +23,7 @@ Each table **has to** have a primary key column, which you specify by setting `p Only one primary key column is allowed. -```Python hl_lines="15 16 17" +```Python hl_lines="15-17" --8<-- "../docs_src/models/docs001.py" ``` @@ -60,7 +60,7 @@ you should get back exactly same value in `response`.). !!!warning pydantic fields have to be always **Optional** and it cannot be changed (otherwise db load validation would fail) -```Python hl_lines="18" +```Python hl_lines="19" --8<-- "../docs_src/models/docs014.py" ``` @@ -73,11 +73,15 @@ Since it can be a function you can set `default=datetime.datetime.now` and get c ```python # <==related of code removed for clarity==> +base_ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + engine=sqlalchemy.create_engine(DATABASE_URL), +) + + class User(ormar.Model): - class Meta: - tablename: str = "users2" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="users2") id: int = ormar.Integer(primary_key=True) email: str = ormar.String(max_length=255, nullable=False) @@ -90,7 +94,7 @@ class User(ormar.Model): ) # <==related of code removed for clarity==> -app =FastAPI() +app = FastAPI() @app.post("/users/") async def create_user(user: User): @@ -134,17 +138,17 @@ If for whatever reason you prefer to change the name in the database but keep th with specifying `name` parameter during Field declaration Here you have a sample model with changed names -```Python hl_lines="16-19" +```Python hl_lines="18-21" --8<-- "../docs_src/models/docs008.py" ``` Note that you can also change the ForeignKey column name -```Python hl_lines="21" +```Python hl_lines="34" --8<-- "../docs_src/models/docs009.py" ``` But for now you cannot change the ManyToMany column names as they go through other Model anyway. -```Python hl_lines="28" +```Python hl_lines="43" --8<-- "../docs_src/models/docs010.py" ``` @@ -152,7 +156,7 @@ But for now you cannot change the ManyToMany column names as they go through oth If you want to customize the queries run by ormar you can define your own queryset class (that extends the ormar `QuerySet`) in your model class, default one is simply the `QuerySet` -You can provide a new class in `Meta` configuration of your class as `queryset_class` parameter. +You can provide a new class in `ormar_config` of your class as `queryset_class` parameter. ```python import ormar @@ -170,12 +174,10 @@ class MyQuerySetClass(QuerySet): class Book(ormar.Model): - - class Meta(ormar.ModelMeta): - metadata = metadata - database = database - tablename = "book" - queryset_class = MyQuerySetClass + ormar_config = base_ormar_config.copy( + queryset_class=MyQuerySetClass, + tablename="book", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=32) @@ -217,9 +219,9 @@ and table creation you need to assign each `Model` with two special parameters. One is `Database` instance created with your database url in [sqlalchemy connection string][sqlalchemy connection string] format. -Created instance needs to be passed to every `Model` with `Meta` class `database` parameter. +Created instance needs to be passed to every `Model` with `ormar_config` object `database` parameter. -```Python hl_lines="1 6 12" +```Python hl_lines="1 5 11" --8<-- "../docs_src/models/docs001.py" ``` @@ -231,9 +233,9 @@ Created instance needs to be passed to every `Model` with `Meta` class `database Second dependency is sqlalchemy `MetaData` instance. -Created instance needs to be passed to every `Model` with `Meta` class `metadata` parameter. +Created instance needs to be passed to every `Model` with `ormar_config` object `metadata` parameter. -```Python hl_lines="2 7 13" +```Python hl_lines="3 6 12" --8<-- "../docs_src/models/docs001.py" ``` @@ -243,25 +245,22 @@ Created instance needs to be passed to every `Model` with `Meta` class `metadata #### Best practice -Only thing that `ormar` expects is a class with name `Meta` and two class variables: `metadata` and `databases`. +Only thing that `ormar` expects is a field with name `ormar_config`. -So instead of providing the same parameters over and over again for all models you should creata a class and subclass it in all models. +So instead of providing the same parameters over and over again for all models +you should creat an object and use its copy in all models. -```Python hl_lines="14 20 33" +```Python hl_lines="9-11 18 27" --8<-- "../docs_src/models/docs013.py" ``` -!!!warning - You need to subclass your `MainMeta` class in each `Model` class as those classes store configuration variables - that otherwise would be overwritten by each `Model`. - ### Table Names By default table name is created from Model class name as lowercase name plus 's'. -You can overwrite this parameter by providing `Meta` class `tablename` argument. +You can overwrite this parameter by providing `ormar_config` object `tablename` argument. -```Python hl_lines="12 13 14" +```Python hl_lines="14-16" --8<-- "../docs_src/models/docs002.py" ``` @@ -279,9 +278,9 @@ Right now only `IndexColumns` and `UniqueColumns` constraints are supported. #### UniqueColumns -You can set this parameter by providing `Meta` class `constraints` argument. +You can set this parameter by providing `ormar_config` object `constraints` argument. -```Python hl_lines="14-17" +```Python hl_lines="13-16" --8<-- "../docs_src/models/docs006.py" ``` @@ -292,9 +291,9 @@ You can set this parameter by providing `Meta` class `constraints` argument. #### IndexColumns -You can set this parameter by providing `Meta` class `constraints` argument. +You can set this parameter by providing `ormar_config` object `constraints` argument. -```Python hl_lines="14-17" +```Python hl_lines="13-16" --8<-- "../docs_src/models/docs017.py" ``` @@ -305,9 +304,9 @@ You can set this parameter by providing `Meta` class `constraints` argument. #### CheckColumns -You can set this parameter by providing `Meta` class `constraints` argument. +You can set this parameter by providing `ormar_config` object `constraints` argument. -```Python hl_lines="14-17" +```Python hl_lines="15-20" --8<-- "../docs_src/models/docs018.py" ``` @@ -319,9 +318,9 @@ You can set this parameter by providing `Meta` class `constraints` argument. As each `ormar.Model` is also a `pydantic` model, you might want to tweak the settings of the pydantic configuration. -The way to do this in pydantic is to adjust the settings on the `Config` class provided to your model, and it works exactly the same for ormar models. +The way to do this in pydantic is to adjust the settings on the `model_config` dictionary provided to your model, and it works exactly the same for ormar models. -So in order to set your own preferences you need to provide not only the `Meta` class but also the `Config` class to your model. +So in order to set your own preferences you need to provide not only the `ormar_config` class but also the `model_config = ConfigDict()` class to your model. !!!note To read more about available settings visit the [pydantic](https://pydantic-docs.helpmanual.io/usage/model_config/) config page. @@ -330,13 +329,11 @@ Note that if you do not provide your own configuration, ormar will do it for you The default config provided is as follows: ```python -class Config(pydantic.BaseConfig): - orm_mode = True - validate_assignment = True +model_config = ConfigDict(validate_assignment=True) ``` So to overwrite setting or provide your own a sample model can look like following: -```Python hl_lines="15-16" +```Python hl_lines="16" --8<-- "../docs_src/models/docs016.py" ``` @@ -348,69 +345,62 @@ If you try to do so the `ModelError` will be raised. Since the extra fields cannot be saved in the database the default to disallow such fields seems a feasible option. -On the contrary in `pydantic` the default option is to ignore such extra fields, therefore `ormar` provides an `Meta.extra` setting to behave in the same way. +On the contrary in `pydantic` the default option is to ignore such extra fields, therefore `ormar` provides an `ormar_config.extra` setting to behave in the same way. To ignore extra fields passed to `ormar` set this setting to `Extra.ignore` instead of default `Extra.forbid`. Note that `ormar` does not allow accepting extra fields, you can only ignore them or forbid them (raise exception if present) ```python -from ormar import Extra +from ormar import Extra, OrmarConfig class Child(ormar.Model): - class Meta(ormar.ModelMeta): - tablename = "children" - metadata = metadata - database = database - extra = Extra.ignore # set extra setting to prevent exceptions on extra fields presence + ormar_config = OrmarConfig( + tablename="children", + extra=Extra.ignore # set extra setting to prevent exceptions on extra fields presence + ) id: int = ormar.Integer(name="child_id", primary_key=True) first_name: str = ormar.String(name="fname", max_length=100) last_name: str = ormar.String(name="lname", max_length=100) ``` -To set the same setting on all model check the [best practices]("../models/index/#best-practice") and `BaseMeta` concept. +To set the same setting on all model check the [best practices]("../models/index/#best-practice") and `base_ormar_config` concept. ## Model sort order When querying the database with given model by default the Model is ordered by the `primary_key` column ascending. If you wish to change the default behaviour you can do it by providing `orders_by` -parameter to model `Meta` class. +parameter to model `ormar_config` object. Sample default ordering: ```python -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - +base_ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), +) -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database # default sort by column id ascending class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) ``` Modified ```python - -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - - -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), +) # now default sort by name descending class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" - orders_by = ["-name"] + ormar_config = base_ormar_config.copy( + orders_by = ["-name"], + tablename="authors", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -425,7 +415,7 @@ There are two ways to create and persist the `Model` instance in the database. If you plan to modify the instance in the later execution of your program you can initiate your `Model` as a normal class and later await a `save()` call. -```Python hl_lines="20 21" +```Python hl_lines="25-26" --8<-- "../docs_src/models/docs007.py" ``` @@ -435,7 +425,7 @@ For creating multiple objects at once a `bulk_create()` QuerySet's method is ava Each model has a `QuerySet` initialised as `objects` parameter -```Python hl_lines="23" +```Python hl_lines="28" --8<-- "../docs_src/models/docs007.py" ``` diff --git a/docs/models/inheritance.md b/docs/models/inheritance.md index 0f4294cd2..36695bd9d 100644 --- a/docs/models/inheritance.md +++ b/docs/models/inheritance.md @@ -32,6 +32,13 @@ To use Mixins just define a class that is not inheriting from an `ormar.Model` b defining `ormar.Fields` as class variables. ```python +base_ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + engine=sqlalchemy.create_engine(DATABASE_URL), +) + + # a mixin defines the fields but is a normal python class class AuditMixin: created_by: str = ormar.String(max_length=100) @@ -45,10 +52,7 @@ class DateFieldsMixins: # a models can inherit from one or more mixins class Category(ormar.Model, DateFieldsMixins, AuditMixin): - class Meta(ormar.ModelMeta): - tablename = "categories" - metadata = metadata - database = db + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -57,7 +61,7 @@ class Category(ormar.Model, DateFieldsMixins, AuditMixin): !!!tip Note that Mixins are **not** models, so you still need to inherit - from `ormar.Model` as well as define `Meta` class in the **final** model. + from `ormar.Model` as well as define `ormar_config` field in the **final** model. A Category class above will have four additional fields: `created_date`, `updated_date`, `created_by` and `updated_by`. @@ -73,11 +77,11 @@ In concept concrete table inheritance is very similar to Mixins, but uses actual `ormar.Models` as base classes. !!!warning - Note that base classes have `abstract=True` set in `Meta` class, if you try + Note that base classes have `abstract=True` set in `ormar_config` object, if you try to inherit from non abstract marked class `ModelDefinitionError` will be raised. Since this abstract Model will never be initialized you can skip `metadata` -and `database` in it's `Meta` definition. +and `database` in it's `ormar_config` definition. But if you provide it - it will be inherited, that way you do not have to provide `metadata` and `databases` in the final/concrete class @@ -91,8 +95,7 @@ otherwise an error will be raised. # note that base classes have abstract=True # since this model will never be initialized you can skip metadata and database class AuditModel(ormar.Model): - class Meta: - abstract = True + ormar_config = base_ormar_config.copy(abstract=True) created_by: str = ormar.String(max_length=100) updated_by: str = ormar.String(max_length=100, default="Sam") @@ -100,10 +103,11 @@ class AuditModel(ormar.Model): # but if you provide it it will be inherited - DRY (Don't Repeat Yourself) in action class DateFieldsModel(ormar.Model): - class Meta: - abstract = True - metadata = metadata - database = db + ormar_config = base_ormar_config.copy( + abstract=True, + metadata=metadata, + database=db, + ) created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now) @@ -111,8 +115,7 @@ class DateFieldsModel(ormar.Model): # that way you do not have to provide metadata and databases in concrete class class Category(DateFieldsModel, AuditModel): - class Meta(ormar.ModelMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -143,12 +146,13 @@ the previously defined one. ```python # base class class DateFieldsModel(ormar.Model): - class Meta: - abstract = True - metadata = metadata - database = db + ormar_config = OrmarConfig( + abstract=True, + metadata=metadata, + database=db, # note that UniqueColumns need sqlalchemy db columns names not the ormar ones - constraints = [ormar.UniqueColumns("creation_date", "modification_date")] + constraints=[ormar.UniqueColumns("creation_date", "modification_date")] + ) created_date: datetime.datetime = ormar.DateTime( default=datetime.datetime.now, name="creation_date" @@ -159,10 +163,11 @@ class DateFieldsModel(ormar.Model): class RedefinedField(DateFieldsModel): - class Meta(ormar.ModelMeta): - tablename = "redefines" - metadata = metadata - database = db + ormar_config = OrmarConfig( + tablename="redefines", + metadata=metadata, + database=db, + ) id: int = ormar.Integer(primary_key=True) # here the created_date is replaced by the String field @@ -170,12 +175,12 @@ class RedefinedField(DateFieldsModel): # you can verify that the final field is correctly declared and created -changed_field = RedefinedField.Meta.model_fields["created_date"] +changed_field = RedefinedField.ormar_config.model_fields["created_date"] assert changed_field.default is None assert changed_field.alias == "creation_date" -assert any(x.name == "creation_date" for x in RedefinedField.Meta.table.columns) +assert any(x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns) assert isinstance( - RedefinedField.Meta.table.columns["creation_date"].type, + RedefinedField.ormar_config.table.columns["creation_date"].type, sqlalchemy.sql.sqltypes.String, ) ``` @@ -225,9 +230,7 @@ That might sound complicated but let's look at the following example: ```python # normal model used in relation class Person(ormar.Model): - class Meta: - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -235,10 +238,7 @@ class Person(ormar.Model): # parent model - needs to be abstract class Car(ormar.Model): - class Meta: - abstract = True - metadata = metadata - database = db + ormar_config = base_ormar_config.copy(abstract=True) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) @@ -249,16 +249,13 @@ class Car(ormar.Model): class Truck(Car): - class Meta: - pass + ormar_config = base_ormar_config.copy() max_capacity: int = ormar.Integer() class Bus(Car): - class Meta: - # default naming is name.lower()+'s' so it's ugly for buss ;) - tablename = "buses" + ormar_config = base_ormar_config.copy(tablename="buses") max_persons: int = ormar.Integer() ``` @@ -266,7 +263,7 @@ class Bus(Car): Now when you will inspect the fields on Person model you will get: ```python -Person.Meta.model_fields +Person.ormar_config.model_fields """ {'id': , 'name': , @@ -293,8 +290,7 @@ different `related_name` parameter. ```python # rest of the above example remains the same class Bus(Car): - class Meta: - tablename = "buses" + ormar_config = base_ormar_config.copy(tablename="buses") # new field that changes the related_name owner: Person = ormar.ForeignKey(Person, related_name="buses") @@ -304,7 +300,7 @@ class Bus(Car): Now the columns looks much better. ```python -Person.Meta.model_fields +Person.ormar_config.model_fields """ {'id': , 'name': , @@ -344,27 +340,18 @@ We will modify the previous example described above to use m2m relation for co_o ```python # person remain the same as above class Person(ormar.Model): - class Meta: - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) # new through model between Person and Car2 class PersonsCar(ormar.Model): - class Meta: - tablename = "cars_x_persons" - metadata = metadata - database = db + ormar_config = base_ormar_config.copy(tablename="cars_x_persons") # note how co_owners is now ManyToMany relation class Car2(ormar.Model): - class Meta: - # parent class needs to be marked abstract - abstract = True - metadata = metadata - database = db + ormar_config = base_ormar_config.copy(abstract=True) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50) @@ -379,16 +366,13 @@ class Car2(ormar.Model): # child models define only additional Fields class Truck2(Car2): - class Meta: - # note how you don't have to provide inherited Meta params - tablename = "trucks2" + ormar_config = base_ormar_config.copy(tablename="trucks2") max_capacity: int = ormar.Integer() class Bus2(Car2): - class Meta: - tablename = "buses2" + ormar_config = base_ormar_config.copy(tablename="busses2") max_persons: int = ormar.Integer() ``` @@ -402,7 +386,7 @@ That way for class Truck2 the relation defined in You can verify the names by inspecting the list of fields present on `Person` model. ```python -Person.Meta.model_fields +Person.ormar_config.model_fields { # note how all relation fields need to be unique on Person # regardless if autogenerated or manually overwritten @@ -425,14 +409,14 @@ But that's not all. It's kind of internal to `ormar` but affects the data struct so let's examine the through models for both `Bus2` and `Truck2` models. ```python -Bus2.Meta.model_fields['co_owners'].through +Bus2.ormar_config.model_fields['co_owners'].through -Bus2.Meta.model_fields['co_owners'].through.Meta.tablename +Bus2.ormar_config.model_fields['co_owners'].through.ormar_config.tablename 'cars_x_persons_buses2' -Truck2.Meta.model_fields['co_owners'].through +Truck2.ormar_config.model_fields['co_owners'].through -Truck2.Meta.model_fields['co_owners'].through.Meta.tablename +Truck2.ormar_config.model_fields['co_owners'].through.ormar_config.tablename 'cars_x_persons_trucks2' ``` @@ -443,7 +427,7 @@ the name of the **table** from the child is used. Note that original model is not only not used, the table for this model is removed from metadata: ```python -Bus2.Meta.metadata.tables.keys() +Bus2.ormar_config.metadata.tables.keys() dict_keys(['test_date_models', 'categories', 'subjects', 'persons', 'trucks', 'buses', 'cars_x_persons_trucks2', 'trucks2', 'cars_x_persons_buses2', 'buses2']) ``` @@ -469,26 +453,24 @@ Ormar allows you to skip certain fields in inherited model that are coming from !!!Note Note that the same behaviour can be achieved by splitting the model into more abstract models and mixins - which is a preferred way in normal circumstances. -To skip certain fields from a child model, list all fields that you want to skip in `model.Meta.exclude_parent_fields` parameter like follows: +To skip certain fields from a child model, list all fields that you want to skip in `model.ormar_config.exclude_parent_fields` parameter like follows: ```python -metadata = sa.MetaData() -db = databases.Database(DATABASE_URL) +base_ormar_config = OrmarConfig( + metadata=sa.MetaData(), + database=databases.Database(DATABASE_URL), +) class AuditModel(ormar.Model): - class Meta: - abstract = True + ormar_config = base_ormar_config.copy(abstract=True) created_by: str = ormar.String(max_length=100) updated_by: str = ormar.String(max_length=100, default="Sam") class DateFieldsModel(ormar.Model): - class Meta(ormar.ModelMeta): - abstract = True - metadata = metadata - database = db + ormar_config = base_ormar_config.copy(abstract=True) created_date: datetime.datetime = ormar.DateTime( default=datetime.datetime.now, name="creation_date" @@ -499,10 +481,11 @@ class DateFieldsModel(ormar.Model): class Category(DateFieldsModel, AuditModel): - class Meta(ormar.ModelMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy( + tablename="categories", # set fields that should be skipped - exclude_parent_fields = ["updated_by", "updated_date"] + exclude_parent_fields=["updated_by", "updated_date"], + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) @@ -523,38 +506,32 @@ Note how you simply need to provide field names and it will exclude the parent f The same effect can be achieved by splitting base classes like: ```python -metadata = sa.MetaData() -db = databases.Database(DATABASE_URL) +base_ormar_config = OrmarConfig( + metadata=sa.MetaData(), + database=databases.Database(DATABASE_URL), +) class AuditCreateModel(ormar.Model): - class Meta: - abstract = True + ormar_config = base_ormar_config.copy(abstract=True) created_by: str = ormar.String(max_length=100) class AuditUpdateModel(ormar.Model): - class Meta: - abstract = True + ormar_config = base_ormar_config.copy(abstract=True) updated_by: str = ormar.String(max_length=100, default="Sam") class CreateDateFieldsModel(ormar.Model): - class Meta(ormar.ModelMeta): - abstract = True - metadata = metadata - database = db + ormar_config = base_ormar_config.copy(abstract=True) created_date: datetime.datetime = ormar.DateTime( default=datetime.datetime.now, name="creation_date" ) class UpdateDateFieldsModel(ormar.Model): - class Meta(ormar.ModelMeta): - abstract = True - metadata = metadata - database = db + ormar_config = base_ormar_config.copy(abstract=True) updated_date: datetime.datetime = ormar.DateTime( default=datetime.datetime.now, name="modification_date" @@ -562,8 +539,7 @@ class UpdateDateFieldsModel(ormar.Model): class Category(CreateDateFieldsModel, AuditCreateModel): - class Meta(ormar.ModelMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=50, unique=True, index=True) diff --git a/docs/models/internals.md b/docs/models/internals.md index 463d368fa..358c31957 100644 --- a/docs/models/internals.md +++ b/docs/models/internals.md @@ -20,27 +20,27 @@ For example to list pydantic model fields you can: ## Sqlalchemy Table -To access auto created sqlalchemy table you can use `Model.Meta.table` parameter +To access auto created sqlalchemy table you can use `Model.ormar_config.table` parameter For example to list table columns you can: -```Python hl_lines="20" +```Python hl_lines="24" --8<-- "../docs_src/models/docs004.py" ``` !!!tip - You can access table primary key name by `Course.Meta.pkname` + You can access table primary key name by `Course.ormar_config.pkname` !!!info For more options visit official [sqlalchemy-metadata][sqlalchemy-metadata] documentation. ## Fields Definition -To access ormar `Fields` you can use `Model.Meta.model_fields` parameter +To access ormar `Fields` you can use `Model.ormar_config.model_fields` parameter For example to list table model fields you can: -```Python hl_lines="20" +```Python hl_lines="22" --8<-- "../docs_src/models/docs005.py" ``` diff --git a/docs/models/methods.md b/docs/models/methods.md index f3f4dd1bb..13fb33e36 100644 --- a/docs/models/methods.md +++ b/docs/models/methods.md @@ -96,10 +96,7 @@ Flag indicates whether fields which were not explicitly set when creating the mo ```python class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="Test") @@ -107,10 +104,7 @@ class Category(ormar.Model): class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -140,20 +134,14 @@ Flag indicates are equal to their default values (whether set or otherwise) shou ```python class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="Test") visibility: bool = ormar.Boolean(default=True) class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -181,10 +169,7 @@ Flag indicates whether fields which are equal to `None` should be excluded from ```python class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="Test", nullable=True) @@ -192,10 +177,7 @@ class Category(ormar.Model): class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -226,10 +208,7 @@ Setting flag to `True` will exclude all primary key columns in a tree, including ```python class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -249,20 +228,14 @@ Setting the `exclude_through_models=True` will exclude all through models, inclu ```python class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta: - tablename = "items" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -321,25 +294,21 @@ That means that this way you can effortlessly create pydantic models for request Given sample ormar models like follows: ```python -metadata = sqlalchemy.MetaData() -database = databases.Database(DATABASE_URL, force_rollback=True) +base_ormar_config = ormar.OrmarConfig( + metadata=sqlalchemy.MetaData(), + database=databases.Database(DATABASE_URL, force_rollback=True), +) -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database - class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Item(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, default="test") @@ -482,10 +451,7 @@ In example: ```python class Movie(ormar.Model): - class Meta: - tablename = "movies" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="title") @@ -584,18 +550,14 @@ Example: ```python class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) department_name: str = ormar.String(max_length=100) class Course(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) course_name: str = ormar.String(max_length=100) @@ -604,9 +566,7 @@ class Course(ormar.Model): class Student(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs/models/migrations.md b/docs/models/migrations.md index 684101456..7577a682e 100644 --- a/docs/models/migrations.md +++ b/docs/models/migrations.md @@ -16,14 +16,14 @@ engine = sqlalchemy.create_engine("sqlite:///test.db") metadata.create_all(engine) ``` -You can also create single tables, sqlalchemy tables are exposed in `ormar.Meta` class. +You can also create single tables, sqlalchemy tables are exposed in `ormar.ormar_config` object. ```python import sqlalchemy # get your database url in sqlalchemy format - same as used with databases instance used in Model definition engine = sqlalchemy.create_engine("sqlite:///test.db") # Artist is an ormar model from previous examples -Artist.Meta.table.create(engine) +Artist.ormar_config.table.create(engine) ``` !!!warning diff --git a/docs/queries/aggregations.md b/docs/queries/aggregations.md index 7a2f9e81c..6294754ff 100644 --- a/docs/queries/aggregations.md +++ b/docs/queries/aggregations.md @@ -32,10 +32,7 @@ the count will be the total number of rows returned ```python class Book(ormar.Model): - class Meta: - tablename = "books" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -60,10 +57,7 @@ Returns a bool value to confirm if there are rows matching the given criteria (a ```python class Book(ormar.Model): - class Meta: - tablename = "books" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) diff --git a/docs/queries/create.md b/docs/queries/create.md index 659e2e257..b10962f3a 100644 --- a/docs/queries/create.md +++ b/docs/queries/create.md @@ -30,10 +30,7 @@ The allowed kwargs are `Model` fields names and proper value types. ```python class Album(ormar.Model): - class Meta: - tablename = "album" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="album") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -68,10 +65,7 @@ i.e. `get_or_create(_defaults: {"title": "I win"}, title="never used")` will alw ```python class Album(ormar.Model): - class Meta: - tablename = "album" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="album") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -106,7 +100,7 @@ assert album == album2 Updates the model, or in case there is no match in database creates a new one. -```Python hl_lines="26-32" +```Python hl_lines="40-48" --8<-- "../docs_src/queries/docs003.py" ``` @@ -122,7 +116,7 @@ Allows you to create multiple objects at once. A valid list of `Model` objects needs to be passed. -```python hl_lines="21-27" +```python hl_lines="26-32" --8<-- "../docs_src/queries/docs004.py" ``` diff --git a/docs/queries/delete.md b/docs/queries/delete.md index aec5171a1..01f2c93fb 100644 --- a/docs/queries/delete.md +++ b/docs/queries/delete.md @@ -26,7 +26,7 @@ If you do not provide this flag or a filter a `QueryDefinitionError` will be rai Return number of rows deleted. -```python hl_lines="26-30" +```python hl_lines="40-44" --8<-- "../docs_src/queries/docs005.py" ``` @@ -59,20 +59,14 @@ If you specify the keep_reversed flag to `False` `ormar` will also delete the re ```python class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) is_best_seller: bool = ormar.Boolean(default=False) class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -104,20 +98,14 @@ If you specify the keep_reversed flag to `False` `ormar` will also delete the re ```python class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) is_best_seller: bool = ormar.Boolean(default=False) class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -148,4 +136,4 @@ await album.tracks.clear() await album.tracks.clear(keep_reversed=False) ``` -[querysetproxy]: ../relations/queryset-proxy.md \ No newline at end of file +[querysetproxy]: ../relations/queryset-proxy.md diff --git a/docs/queries/filter-and-sort.md b/docs/queries/filter-and-sort.md index 7d9637f4b..1888a6b17 100644 --- a/docs/queries/filter-and-sort.md +++ b/docs/queries/filter-and-sort.md @@ -35,20 +35,14 @@ a filter across an FK relationship. ```python class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) is_best_seller: bool = ormar.Boolean(default=False) class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -197,20 +191,14 @@ conditions. ```python class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) is_best_seller: bool = ormar.Boolean(default=False) class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -245,26 +233,21 @@ Since it sounds more complicated than it is, let's look at some examples. Given a sample models like this: ```python -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() - - -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -808,7 +791,7 @@ Since order of rows in a database is not guaranteed, `ormar` **always** issues a When querying the database with given model by default the `Model` is ordered by the `primary_key` column ascending. If you wish to change the default behaviour you can do it by providing `orders_by` -parameter to model `Meta` class. +parameter to `ormar_config`. !!!tip To read more about models sort order visit [models](../models/index.md#model-sort-order) section of documentation @@ -823,8 +806,8 @@ Order in which order_by clauses are applied is as follows: * Explicitly passed `order_by()` calls in query * Relation passed `orders_by` and `related_orders_by` if exists - * Model `Meta` class `orders_by` - * Model `primary_key` column ascending (fallback, used if none of above provided) + * Model's `ormar_config` object `orders_by` + * Model's `primary_key` column ascending (fallback, used if none of above provided) **Order from only one source is applied to each `Model` (so that you can always overwrite it in a single query).** diff --git a/docs/queries/joins-and-subqueries.md b/docs/queries/joins-and-subqueries.md index cd840e827..bc0b0a06a 100644 --- a/docs/queries/joins-and-subqueries.md +++ b/docs/queries/joins-and-subqueries.md @@ -46,20 +46,14 @@ To chain related `Models` relation use double underscores between names. ```python class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) is_best_seller: bool = ormar.Boolean(default=False) class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -82,10 +76,7 @@ You can provide a string or a list of strings (or a field/ list of fields) ```python class SchoolClass(ormar.Model): - class Meta: - tablename = "schoolclasses" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="schoolclasses") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -93,20 +84,14 @@ class SchoolClass(ormar.Model): class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Student(ormar.Model): - class Meta: - tablename = "students" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -115,10 +100,7 @@ class Student(ormar.Model): class Teacher(ormar.Model): - class Meta: - tablename = "teachers" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -182,18 +164,14 @@ If `follow=True` is set it adds also related models of related models. With sample date like follow: ```python -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - - -class BaseMeta(ormar.ModelMeta): - database = database - metadata = metadata +base_ormar_config = OrmarConfig( + database=databases.Database(DATABASE_URL, force_rollback=True), + metadata=sqlalchemy.MetaData(), +) class Address(ormar.Model): - class Meta(BaseMeta): - tablename = "addresses" + ormar_config = base_ormar_config.copy(tablename="addresses") id: int = ormar.Integer(primary_key=True) street: str = ormar.String(max_length=100, nullable=False) @@ -203,8 +181,7 @@ class Address(ormar.Model): class Branch(ormar.Model): - class Meta(BaseMeta): - tablename = "branches" + ormar_config = base_ormar_config.copy(tablename="branches") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False) @@ -212,8 +189,7 @@ class Branch(ormar.Model): class Company(ormar.Model): - class Meta(BaseMeta): - tablename = "companies" + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100, nullable=False, name="company_name") @@ -264,20 +240,14 @@ To chain related `Models` relation use double underscores between names. ```python class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) is_best_seller: bool = ormar.Boolean(default=False) class Track(ormar.Model): - class Meta: - tablename = "tracks" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -301,10 +271,7 @@ You can provide a string, or a list of strings ```python class SchoolClass(ormar.Model): - class Meta: - tablename = "schoolclasses" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="schoolclasses") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -312,20 +279,14 @@ class SchoolClass(ormar.Model): class Category(ormar.Model): - class Meta: - tablename = "categories" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Student(ormar.Model): - class Meta: - tablename = "students" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -334,10 +295,7 @@ class Student(ormar.Model): class Teacher(ormar.Model): - class Meta: - tablename = "teachers" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs/queries/pagination-and-rows-number.md b/docs/queries/pagination-and-rows-number.md index 21f41912d..c810ac6cb 100644 --- a/docs/queries/pagination-and-rows-number.md +++ b/docs/queries/pagination-and-rows-number.md @@ -22,10 +22,7 @@ Combines the `offset` and `limit` methods based on page number and size ```python class Track(ormar.Model): - class Meta: - tablename = "track" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="track") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -52,10 +49,7 @@ use the `limit_raw_sql` parameter flag, and set it to `True`. ```python class Track(ormar.Model): - class Meta: - tablename = "track" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="track") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -86,10 +80,7 @@ use the `limit_raw_sql` parameter flag, and set it to `True`. ```python class Track(ormar.Model): - class Meta: - tablename = "track" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="track") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) diff --git a/docs/queries/raw-data.md b/docs/queries/raw-data.md index 57e027356..00941fc47 100644 --- a/docs/queries/raw-data.md +++ b/docs/queries/raw-data.md @@ -40,8 +40,7 @@ Example: # declared models class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) @@ -49,8 +48,7 @@ class Category(ormar.Model): class Post(ormar.Model): - class Meta(BaseMeta): - tablename = "posts" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200) @@ -83,16 +81,14 @@ Note how nested models columns will be prefixed with full relation path coming f # declare models class User(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Role(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -216,8 +212,7 @@ Example: # declared models class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) @@ -225,8 +220,7 @@ class Category(ormar.Model): class Post(ormar.Model): - class Meta(BaseMeta): - tablename = "posts" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200) @@ -257,8 +251,7 @@ Let's complicate the relation and modify the previously mentioned Category model ```python class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) diff --git a/docs/queries/read.md b/docs/queries/read.md index 018d69311..295234b14 100644 --- a/docs/queries/read.md +++ b/docs/queries/read.md @@ -31,10 +31,7 @@ Passing a criteria is actually calling filter(*args, **kwargs) method described ```python class Track(ormar.Model): - class Meta: - tablename = "track" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="track") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -74,10 +71,7 @@ a new one with given kwargs and _defaults. ```python class Album(ormar.Model): - class Meta: - tablename = "album" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="album") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -114,10 +108,7 @@ Gets the first row from the db ordered by primary key column ascending. ```python class Album(ormar.Model): - class Meta: - tablename = "album" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="album") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -143,20 +134,14 @@ If there are no rows meeting the criteria an empty list is returned. ```python class Album(ormar.Model): - class Meta: - tablename = "album" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="album") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Track(ormar.Model): - class Meta: - tablename = "track" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="track") id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -186,10 +171,7 @@ If there are no rows meeting the criteria an empty async generator is returned. ```python class Album(ormar.Model): - class Meta: - tablename = "album" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="album") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs/queries/select-columns.md b/docs/queries/select-columns.md index d5c6c765d..2185c4b27 100644 --- a/docs/queries/select-columns.md +++ b/docs/queries/select-columns.md @@ -35,10 +35,7 @@ metadata = sqlalchemy.MetaData() class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -46,10 +43,7 @@ class Company(ormar.Model): class Car(ormar.Model): - class Meta: - tablename = "cars" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) manufacturer = ormar.ForeignKey(Company) @@ -208,15 +202,14 @@ import sqlalchemy import ormar from tests.settings import DATABASE_URL -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() +base_ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL, force_rollback=True), + metadata=sqlalchemy.MetaData(), +) class Company(ormar.Model): - class Meta: - tablename = "companies" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy(tablename="companies") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -224,10 +217,7 @@ class Company(ormar.Model): class Car(ormar.Model): - class Meta: - tablename = "cars" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) manufacturer = ormar.ForeignKey(Company) diff --git a/docs/queries/update.md b/docs/queries/update.md index 642f04407..f9f00e901 100644 --- a/docs/queries/update.md +++ b/docs/queries/update.md @@ -29,7 +29,7 @@ If you do not provide this flag or a filter a `QueryDefinitionError` will be rai Return number of rows updated. -```Python hl_lines="26-28" +```Python hl_lines="42-44" --8<-- "../docs_src/queries/docs002.py" ``` @@ -44,7 +44,7 @@ Return number of rows updated. Updates the model, or in case there is no match in database creates a new one. -```Python hl_lines="26-32" +```Python hl_lines="40-48" --8<-- "../docs_src/queries/docs003.py" ``` @@ -123,4 +123,4 @@ from other side of the relation. [querysetproxy]: ../relations/queryset-proxy.md [models-upsert]: ../models/methods.md#upsert -[models-save-related]: ../models/methods.md#save_related \ No newline at end of file +[models-save-related]: ../models/methods.md#save_related diff --git a/docs/relations/foreign-key.md b/docs/relations/foreign-key.md index 2f880a1e9..5860ad2dc 100644 --- a/docs/relations/foreign-key.md +++ b/docs/relations/foreign-key.md @@ -14,7 +14,7 @@ Sqlalchemy column and Type are automatically taken from target `Model`. To define a relation add `ForeignKey` field that points to related `Model`. -```Python hl_lines="29" +```Python hl_lines="30" --8<-- "../docs_src/fields/docs003.py" ``` @@ -24,7 +24,7 @@ To define a relation add `ForeignKey` field that points to related `Model`. By default it's child (source) `Model` name + s, like courses in snippet below: -```Python hl_lines="29 35" +```Python hl_lines="29 36" --8<-- "../docs_src/fields/docs001.py" ``` @@ -52,8 +52,7 @@ Example: ```python class Author(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=80) @@ -61,8 +60,7 @@ class Author(ormar.Model): class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -175,7 +173,7 @@ To read which methods of QuerySet are available read below [querysetproxy][query But you can overwrite this name by providing `related_name` parameter like below: -```Python hl_lines="29 35" +```Python hl_lines="27-29 35" --8<-- "../docs_src/fields/docs002.py" ``` @@ -230,7 +228,7 @@ You have several ways to set-up a relationship connection. The most obvious one is to pass a related `Model` instance to the constructor. -```Python hl_lines="34-35" +```Python hl_lines="35-36" --8<-- "../docs_src/relations/docs001.py" ``` @@ -238,7 +236,7 @@ The most obvious one is to pass a related `Model` instance to the constructor. You can setup the relation also with just the pk column value of the related model. -```Python hl_lines="37-38" +```Python hl_lines="38-39" --8<-- "../docs_src/relations/docs001.py" ``` @@ -248,7 +246,7 @@ Next option is with a dictionary of key-values of the related model. You can build the dictionary yourself or get it from existing model with `model_dump()` method. -```Python hl_lines="40-41" +```Python hl_lines="41-42" --8<-- "../docs_src/relations/docs001.py" ``` @@ -256,7 +254,7 @@ You can build the dictionary yourself or get it from existing model with `model_ Finally you can explicitly set it to None (default behavior if no value passed). -```Python hl_lines="43-44" +```Python hl_lines="44-45" --8<-- "../docs_src/relations/docs001.py" ``` @@ -283,4 +281,4 @@ Finally you can explicitly set it to None (default behavior if no value passed). [fields]: ./queries.md#fields [exclude_fields]: ./queries.md#exclude_fields [order_by]: ./queries.md#order_by -[server_default]: ../fields/common-parameters.md#server-default \ No newline at end of file +[server_default]: ../fields/common-parameters.md#server-default diff --git a/docs/relations/index.md b/docs/relations/index.md index 385516a8e..979e766e5 100644 --- a/docs/relations/index.md +++ b/docs/relations/index.md @@ -13,7 +13,7 @@ To read more about methods, possibilities, definition etc. please read the subse To define many-to-one relation use `ForeignKey` field. -```Python hl_lines="17" +```Python hl_lines="26" --8<-- "../docs_src/relations/docs003.py" ``` @@ -24,13 +24,11 @@ To define many-to-one relation use `ForeignKey` field. The definition of one-to-many relation also uses `ForeignKey`, and it's registered for you automatically. -So in relation ato example above. +So in relation to example above. -```Python hl_lines="17" +```Python hl_lines="8" class Department(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -54,19 +52,20 @@ To define many-to-many relation use `ManyToMany` field. ```python hl_lines="18" class Category(ormar.Model): - class Meta: - tablename = "categories" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="categories", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - class Meta: - tablename = "posts" - database = database - metadata = metadata + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -92,18 +91,24 @@ side of the current query for m2m models. So if you query from model `A` to model `B`, only model `B` has through field exposed. Which kind of make sense, since it's a one through model/field for each of related models. -```python hl_lines="10-15" +```python hl_lines="12-20" class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="categories", + ) id = ormar.Integer(primary_key=True) name = ormar.String(max_length=40) # you can specify additional fields on through model class PostCategory(ormar.Model): - class Meta(BaseMeta): - tablename = "posts_x_categories" + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="posts_x_categories", + ) id: int = ormar.Integer(primary_key=True) sort_order: int = ormar.Integer(nullable=True) @@ -111,8 +116,10 @@ class PostCategory(ormar.Model): class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -130,7 +137,7 @@ class Post(ormar.Model): ## Relationship default sort order -By default relations follow model default sort order so `primary_key` column ascending, or any sort order se in `Meta` class. +By default relations follow model default sort order so `primary_key` column ascending, or any sort order se in `ormar_config` object. !!!tip To read more about models sort order visit [models](../models/index.md#model-sort-order) section of documentation @@ -143,27 +150,26 @@ columns also `Through` model columns `{through_field_name}__{column_name}` Sample configuration might look like this: -```python hl_lines="24" +```python hl_lines="23" database = databases.Database(DATABASE_URL) metadata = sqlalchemy.MetaData() -class BaseMeta(ormar.ModelMeta): - metadata = metadata - database = database +base_ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, +) class Author(ormar.Model): - class Meta(BaseMeta): - tablename = "authors" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - class Meta(BaseMeta): - tablename = "books" + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey( @@ -186,14 +192,12 @@ In order to create auto-relation or create two models that reference each other different relations (remember the reverse side is auto-registered for you), you need to use `ForwardRef` from `typing` module. -```python hl_lines="1 11 14" +```python hl_lines="1 9 12" PersonRef = ForwardRef("Person") class Person(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -210,4 +214,4 @@ Person.update_forward_refs() [foreign-keys]: ./foreign-key.md [many-to-many]: ./many-to-many.md [queryset-proxy]: ./queryset-proxy.md -[postponed-annotations]: ./postponed-annotations.md \ No newline at end of file +[postponed-annotations]: ./postponed-annotations.md diff --git a/docs/relations/many-to-many.md b/docs/relations/many-to-many.md index ae231e984..de9bc108e 100644 --- a/docs/relations/many-to-many.md +++ b/docs/relations/many-to-many.md @@ -9,7 +9,7 @@ Sqlalchemy column and Type are automatically taken from target `Model`. ## Defining Models -```Python hl_lines="40" +```Python hl_lines="34" --8<-- "../docs_src/relations/docs002.py" ``` @@ -28,16 +28,14 @@ By default it's child (source) `Model` name + s, like courses in snippet below: ```python class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -96,16 +94,14 @@ Example: ```python class Category(ormar.Model): - class Meta(BaseMeta): - tablename = "categories" + ormar_config = base_ormar_config.copy(tablename="categories") id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=40) class Post(ormar.Model): - class Meta(BaseMeta): - pass + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -141,7 +137,7 @@ assert len(categories) == 1 Optionally if you want to add additional fields you can explicitly create and pass the through model class. -```Python hl_lines="14-20 29" +```Python hl_lines="19-24 32" --8<-- "../docs_src/relations/docs004.py" ``` @@ -170,9 +166,7 @@ So in example like this: ```python ... # course declaration omitted class Student(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -180,10 +174,7 @@ class Student(ormar.Model): # will produce default Through model like follows (example simplified) class StudentCourse(ormar.Model): - class Meta: - database = database - metadata = metadata - tablename = "students_courses" + ormar_config = base_ormar_config.copy(tablename="students_courses") id: int = ormar.Integer(primary_key=True) student = ormar.ForeignKey(Student) # default name @@ -199,10 +190,14 @@ Example: ```python ... # course declaration omitted +base_ormar_config = ormar.OrmarConfig( + database=databases.Database("sqlite:///db.sqlite"), + metadata=sqlalchemy.MetaData(), +) + + class Student(ormar.Model): - class Meta: - database = database - metadata = metadata + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -212,10 +207,7 @@ class Student(ormar.Model): # will produce Through model like follows (example simplified) class StudentCourse(ormar.Model): - class Meta: - database = database - metadata = metadata - tablename = "students_courses" + ormar_config = base_ormar_config.copy(tablename="student_courses") id: int = ormar.Integer(primary_key=True) student_id = ormar.ForeignKey(Student) # set by through_relation_name @@ -238,7 +230,7 @@ so it's useful only when additional fields are provided on `Through` model. In a sample model setup as following: -```Python hl_lines="14-20 29" +```Python hl_lines="19-24 32" --8<-- "../docs_src/relations/docs004.py" ``` diff --git a/docs/relations/postponed-annotations.md b/docs/relations/postponed-annotations.md index e15629611..5907f8a34 100644 --- a/docs/relations/postponed-annotations.md +++ b/docs/relations/postponed-annotations.md @@ -36,9 +36,7 @@ PersonRef = ForwardRef("Person") class Person(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -72,9 +70,7 @@ PersonRef = ForwardRef("Person") class Person(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -93,14 +89,10 @@ and through parameters. ChildRef = ForwardRef("Child") class ChildFriend(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() class Child(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -132,9 +124,7 @@ TeacherRef = ForwardRef("Teacher") class Student(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -144,16 +134,11 @@ class Student(ormar.Model): class StudentTeacher(ormar.Model): - class Meta(ModelMeta): - tablename = 'students_x_teachers' - metadata = metadata - database = db + ormar_config = base_ormar_config.copy(tablename='students_x_teachers') class Teacher(ormar.Model): - class Meta(ModelMeta): - metadata = metadata - database = db + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -168,4 +153,4 @@ Student.update_forward_refs() !!!warning Remember that `related_name` needs to be unique across related models regardless - of how many relations are defined. \ No newline at end of file + of how many relations are defined. diff --git a/docs/relations/queryset-proxy.md b/docs/relations/queryset-proxy.md index fa70d6f41..90c89fbfb 100644 --- a/docs/relations/queryset-proxy.md +++ b/docs/relations/queryset-proxy.md @@ -127,7 +127,7 @@ provided Through model. Given sample like this: -```Python hl_lines="14-20 29" +```Python hl_lines="19-24 32" --8<-- "../docs_src/relations/docs004.py" ``` @@ -174,7 +174,7 @@ Updates the related model with provided keyword arguments, return number of upda Note that for `ManyToMany` relations update can also accept an argument with through field name and a dictionary of fields. -```Python hl_lines="14-20 29" +```Python hl_lines="19-24 32" --8<-- "../docs_src/relations/docs004.py" ``` diff --git a/docs/signals.md b/docs/signals.md index 2c33eebdd..cdd7b7601 100644 --- a/docs/signals.md +++ b/docs/signals.md @@ -14,15 +14,15 @@ import sqlalchemy import ormar -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() + +base_ormar_config = ormar.OrmarConfig( + database=databases.Database("sqlite:///db.sqlite"), + metadata=sqlalchemy.MetaData(), +) class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -34,7 +34,7 @@ You can for example define a trigger that will set `album.is_best_seller` status Import `pre_update` decorator, for list of currently available decorators/ signals check below. -```Python hl_lines="1" +```Python hl_lines="7" --8<-- "../docs_src/signals/docs002.py" ``` @@ -54,7 +54,7 @@ for which you want to run the signal receiver. Currently there is no way to set signal for all models at once without explicitly passing them all into registration of receiver. -```Python hl_lines="4-7" +```Python hl_lines="27-30" --8<-- "../docs_src/signals/docs002.py" ``` @@ -65,7 +65,7 @@ Currently there is no way to set signal for all models at once without explicitl Note that our newly created function has instance and class of the instance so you can easily run database queries inside your receivers if you want to. -```Python hl_lines="15-22" +```Python hl_lines="40-47" --8<-- "../docs_src/signals/docs002.py" ``` @@ -106,7 +106,7 @@ class AlbumAuditor: auditor = AlbumAuditor() pre_save(Album)(auditor.before_save) # call above has same result like the one below -Album.Meta.signals.pre_save.connect(auditor.before_save) +Album.ormar_config.signals.pre_save.connect(auditor.before_save) # signals are also exposed on instance album = Album(name='Miami') album.signals.pre_save.connect(auditor.before_save) @@ -127,7 +127,7 @@ async def before_update(sender, instance, **kwargs): instance.is_best_seller = True # disconnect given function from signal for given Model -Album.Meta.signals.pre_save.disconnect(before_save) +Album.ormar_config.signals.pre_save.disconnect(before_save) # signals are also exposed on instance album = Album(name='Miami') album.signals.pre_save.disconnect(before_save) @@ -251,23 +251,23 @@ import sqlalchemy import ormar -database = databases.Database("sqlite:///db.sqlite") -metadata = sqlalchemy.MetaData() + +base_ormar_config = ormar.OrmarConfig( + database=databases.Database("sqlite:///db.sqlite"), + metadata=sqlalchemy.MetaData(), +) class Album(ormar.Model): - class Meta: - tablename = "albums" - metadata = metadata - database = database + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) is_best_seller: bool = ormar.Boolean(default=False) play_count: int = ormar.Integer(default=0) -Album.Meta.signals.your_custom_signal = ormar.Signal() -Album.Meta.signals.your_custom_signal.connect(your_receiver_name) +Album.ormar_config.signals.your_custom_signal = ormar.Signal() +Album.ormar_config.signals.your_custom_signal.connect(your_receiver_name) ``` Actually under the hood signal is a `SignalEmitter` instance that keeps a dictionary of know signals, and allows you @@ -276,13 +276,13 @@ to access them as attributes. When you try to access a signal that does not exis So example above can be simplified to. The `Signal` will be created for you. ``` -Album.Meta.signals.your_custom_signal.connect(your_receiver_name) +Album.ormar_config.signals.your_custom_signal.connect(your_receiver_name) ``` Now to trigger this signal you need to call send method of the Signal. ```python -await Album.Meta.signals.your_custom_signal.send(sender=Album) +await Album.ormar_config.signals.your_custom_signal.send(sender=Album) ``` Note that sender is the only required parameter and it should be ormar Model class. @@ -290,6 +290,6 @@ Note that sender is the only required parameter and it should be ormar Model cla Additional parameters have to be passed as keyword arguments. ```python -await Album.Meta.signals.your_custom_signal.send(sender=Album, my_param=True) +await Album.ormar_config.signals.your_custom_signal.send(sender=Album, my_param=True) ``` diff --git a/docs/transactions.md b/docs/transactions.md index b764192ca..d4d28a250 100644 --- a/docs/transactions.md +++ b/docs/transactions.md @@ -15,10 +15,10 @@ async with database.transaction(): ``` !!!note - Note that it has to be the same `database` that the one used in Model's `Meta` class. + Note that it has to be the same `database` that the one used in Model's `ormar_config` object. To avoid passing `database` instance around in your code you can extract the instance from each `Model`. -Database provided during declaration of `ormar.Model` is available through `Meta.database` and can +Database provided during declaration of `ormar.Model` is available through `ormar_config.database` and can be reached from both class and instance. ```python @@ -26,24 +26,25 @@ import databases import sqlalchemy import ormar -metadata = sqlalchemy.MetaData() -database = databases.Database("sqlite:///") + +base_ormar_config = OrmarConfig( + metadata=sqlalchemy.MetaData(), + database = databases.Database("sqlite:///"), +) + class Author(ormar.Model): - class Meta: - database=database - metadata=metadata + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=255) # database is accessible from class -database = Author.Meta.database +database = Author.ormar_config.database # as well as from instance author = Author(name="Stephen King") -database = author.Meta.database - +database = author.ormar_config.database ``` You can also use `.transaction()` as a function decorator on any async function: diff --git a/docs_src/signals/docs002.py b/docs_src/signals/docs002.py index fd42ed337..0795d67fb 100644 --- a/docs_src/signals/docs002.py +++ b/docs_src/signals/docs002.py @@ -9,7 +9,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/examples/script_from_readme.py b/examples/script_from_readme.py index b50d2dc5e..e00db6516 100644 --- a/examples/script_from_readme.py +++ b/examples/script_from_readme.py @@ -6,16 +6,15 @@ import sqlalchemy DATABASE_URL = "sqlite:///db.sqlite" -database = databases.Database(DATABASE_URL) -metadata = sqlalchemy.MetaData() # note that this step is optional -> all ormar cares is an individual # OrmarConfig for each of the models, but this way you do not # have to repeat the same parameters if you use only one database base_ormar_config = ormar.OrmarConfig( - metadata=metadata, - database=database, + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + engine=sqlalchemy.create_engine(DATABASE_URL), ) # Note that all type hints are optional @@ -28,15 +27,14 @@ class Author(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="authors") + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class Book(ormar.Model): - - ormar_config = base_ormar_config.copy(tablename="books") + ormar_config = base_ormar_config.copy() id: int = ormar.Integer(primary_key=True) author: Optional[Author] = ormar.ForeignKey(Author) @@ -47,10 +45,9 @@ class Book(ormar.Model): # create the database # note that in production you should use migrations # note that this is not required if you connect to existing database -engine = sqlalchemy.create_engine(DATABASE_URL) # just to be sure we clear the db before -metadata.drop_all(engine) -metadata.create_all(engine) +base_ormar_config.metadata.drop_all(base_ormar_config.engine) +base_ormar_config.metadata.create_all(base_ormar_config.engine) # all functions below are divided into functionality categories @@ -378,7 +375,7 @@ async def raw_data(): async def with_connect(function): # note that for any other backend than sqlite you actually need to # connect to the database to perform db operations - async with database: + async with base_ormar_config.database: await function() # note that if you use framework like `fastapi` you shouldn't connect @@ -408,4 +405,4 @@ async def with_connect(function): asyncio.run(with_connect(func)) # drop the database tables -metadata.drop_all(engine) +base_ormar_config.metadata.drop_all(base_ormar_config.engine) From 280acc15f033e96784c1acfe4beaaaf7c63cf066 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 10 Mar 2024 17:05:42 +0100 Subject: [PATCH 88/95] proofread and fix the docs, part 1 --- docs/index.md | 12 ++------ docs/install.md | 11 ++++--- docs/models/index.md | 59 +++++++++++++++++++------------------- docs/models/inheritance.md | 2 +- docs_src/models/docs013.py | 3 +- 5 files changed, 42 insertions(+), 45 deletions(-) diff --git a/docs/index.md b/docs/index.md index 88b27340d..18ccc4768 100644 --- a/docs/index.md +++ b/docs/index.md @@ -21,7 +21,7 @@ ### Overview -The `ormar` package is an async mini ORM for Python, with support for **Postgres, +The `ormar` package is an async ORM for Python, with support for **Postgres, MySQL**, and **SQLite**. The main benefits of using `ormar` are: @@ -53,13 +53,7 @@ Yet remember that those are - well - tests and not all solutions are suitable to ### Part of the `fastapi` ecosystem -As part of the fastapi ecosystem `ormar` is supported in libraries that somehow work with databases. - -As of now `ormar` is supported by: - -* [`fastapi-users`](https://github.com/frankie567/fastapi-users) -* [`fastapi-crudrouter`](https://github.com/awtkns/fastapi-crudrouter) -* [`fastapi-pagination`](https://github.com/uriyyo/fastapi-pagination) +As part of the fastapi ecosystem `ormar` is supported in selected libraries that somehow work with databases. Ormar remains sql dialect agnostic - so only columns working in all supported backends are implemented. @@ -76,7 +70,6 @@ Ormar is built with: * [`sqlalchemy core`][sqlalchemy-core] for query building. * [`databases`][databases] for cross-database async support. * [`pydantic`][pydantic] for data validation. - * `typing_extensions` for python 3.6 - 3.7 ### License @@ -658,7 +651,6 @@ The following keyword arguments are supported on all field types. * `server_default: Any` * `index: bool` * `unique: bool` - * `choices: typing.Sequence` * `name: str` All fields are required unless one of the following is set: diff --git a/docs/install.md b/docs/install.md index 7ba4afd9e..fbaff91c1 100644 --- a/docs/install.md +++ b/docs/install.md @@ -13,22 +13,25 @@ Ormar uses `databases` for connectivity issues, `pydantic` for validation and `s All three should install along the installation of ormar if not present at your system before. * databases -* pydantic>=1.5 +* pydantic * sqlalchemy +The required versions are pinned in the pyproject.toml file. ## Optional dependencies *ormar* has three optional dependencies based on database backend you use: -### Postgresql +### Database backend + +#### Postgresql ```py pip install ormar[postgresql] ``` Will install also `asyncpg` and `psycopg2`. -### Mysql +#### Mysql ```py pip install ormar[mysql] @@ -36,7 +39,7 @@ pip install ormar[mysql] Will install also `aiomysql` and `pymysql`. -### Sqlite +#### Sqlite ```py pip install ormar[sqlite] diff --git a/docs/models/index.md b/docs/models/index.md index 05ebcdbb6..2272e43cc 100644 --- a/docs/models/index.md +++ b/docs/models/index.md @@ -67,12 +67,14 @@ you should get back exactly same value in `response`.). If you set pydantic field with `default` parameter and do not pass actual value in request you will always get default value. Since it can be a function you can set `default=datetime.datetime.now` and get current timestamp each time you call an endpoint etc. +#### Non Database Fields in Fastapi + !!!note Note, that both pydantic and calculated_fields decorated field can be included/excluded in both `model_dump()` and `fastapi` response with `include`/`exclude` and `response_model_include`/`response_model_exclude` accordingly. ```python -# <==related of code removed for clarity==> +# <==part of related code removed for clarity==> base_ormar_config = ormar.OrmarConfig( database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData(), @@ -93,14 +95,14 @@ class User(ormar.Model): default=datetime.datetime.now ) -# <==related of code removed for clarity==> +# <==part of related code removed for clarity==> app = FastAPI() @app.post("/users/") async def create_user(user: User): return await user.save() -# <==related of code removed for clarity==> +# <==part of related code removed for clarity==> def test_excluding_fields_in_endpoints(): client = TestClient(app) @@ -127,7 +129,7 @@ def test_excluding_fields_in_endpoints(): assert response.json().get("timestamp") == str(timestamp).replace(" ", "T") -# <==related of code removed for clarity==> +# <==part of related code removed for clarity==> ``` #### Fields names vs Column names @@ -152,7 +154,7 @@ But for now you cannot change the ManyToMany column names as they go through oth --8<-- "../docs_src/models/docs010.py" ``` -## Overwriting the default QuerySet +### Overwriting the default QuerySet If you want to customize the queries run by ormar you can define your own queryset class (that extends the ormar `QuerySet`) in your model class, default one is simply the `QuerySet` @@ -188,9 +190,9 @@ book = await Book.objects.first_or_404(name="123") ``` -### Type Hints & Legacy +### Type Hints -From version >=0.4.0 `ormar` switched to new notation. +Note that for better IDE support and mypy checks you can provide type hints. ```Python hl_lines="15-17" --8<-- "../docs_src/models/docs001.py" @@ -245,12 +247,12 @@ Created instance needs to be passed to every `Model` with `ormar_config` object #### Best practice -Only thing that `ormar` expects is a field with name `ormar_config`. - +Note that `ormar` expects the field with name `ormar_config` that is an instance of `OrmarConfig` class. +To ease the config management, the `OrmarConfig` class provide `copy` method. So instead of providing the same parameters over and over again for all models -you should creat an object and use its copy in all models. +you should create a base object and use its copy in all models. -```Python hl_lines="9-11 18 27" +```Python hl_lines="9-12 19 28" --8<-- "../docs_src/models/docs013.py" ``` @@ -258,7 +260,7 @@ you should creat an object and use its copy in all models. By default table name is created from Model class name as lowercase name plus 's'. -You can overwrite this parameter by providing `ormar_config` object `tablename` argument. +You can overwrite this parameter by providing `ormar_config` object's `tablename` argument. ```Python hl_lines="14-16" --8<-- "../docs_src/models/docs002.py" @@ -268,10 +270,10 @@ You can overwrite this parameter by providing `ormar_config` object `tablename` On a model level you can also set model-wise constraints on sql columns. -Right now only `IndexColumns` and `UniqueColumns` constraints are supported. +Right now only `IndexColumns`, `UniqueColumns` and `CheckColumns` constraints are supported. !!!note - Note that both constraints should be used only if you want to set a name on constraint or want to set the index on multiple columns, otherwise `index` and `unique` properties on ormar fields are preferred. + Note that both constraints should be used only if you want to set a name on constraint or want to set the index on multiple columns, otherwise `index` and `unique` properties on ormar fields are preferred. !!!tip To read more about columns constraints like `primary_key`, `unique`, `ForeignKey` etc. visit [fields][fields]. @@ -285,9 +287,9 @@ You can set this parameter by providing `ormar_config` object `constraints` argu ``` !!!note - Note that constraints are meant for combination of columns that should be unique. - To set one column as unique use [`unique`](../fields/common-parameters.md#unique) common parameter. - Of course you can set many columns as unique with this param but each of them will be checked separately. + Note that constraints are meant for combination of columns that should be unique. + To set one column as unique use [`unique`](../fields/common-parameters.md#unique) common parameter. + Of course you can set many columns as unique with this param but each of them will be checked separately. #### IndexColumns @@ -298,9 +300,9 @@ You can set this parameter by providing `ormar_config` object `constraints` argu ``` !!!note - Note that constraints are meant for combination of columns that should be in the index. - To set one column index use [`unique`](../fields/common-parameters.md#index) common parameter. - Of course, you can set many columns as indexes with this param but each of them will be a separate index. + Note that constraints are meant for combination of columns that should be in the index. + To set one column index use [`unique`](../fields/common-parameters.md#index) common parameter. + Of course, you can set many columns as indexes with this param but each of them will be a separate index. #### CheckColumns @@ -311,7 +313,7 @@ You can set this parameter by providing `ormar_config` object `constraints` argu ``` !!!note - Note that some databases do not actively support check constraints such as MySQL. + Note that some databases do not actively support check constraints (such as MySQL). ### Pydantic configuration @@ -323,13 +325,13 @@ The way to do this in pydantic is to adjust the settings on the `model_config` d So in order to set your own preferences you need to provide not only the `ormar_config` class but also the `model_config = ConfigDict()` class to your model. !!!note - To read more about available settings visit the [pydantic](https://pydantic-docs.helpmanual.io/usage/model_config/) config page. + To read more about available settings visit the [pydantic](https://pydantic-docs.helpmanual.io/usage/model_config/) config page. Note that if you do not provide your own configuration, ormar will do it for you. The default config provided is as follows: ```python -model_config = ConfigDict(validate_assignment=True) +model_config = ConfigDict(validate_assignment=True, ser_json_bytes="base64") ``` So to overwrite setting or provide your own a sample model can look like following: @@ -373,7 +375,7 @@ When querying the database with given model by default the Model is ordered by t column ascending. If you wish to change the default behaviour you can do it by providing `orders_by` parameter to model `ormar_config` object. -Sample default ordering: +Sample default ordering (not specified - so by primary key): ```python base_ormar_config = ormar.OrmarConfig( database=databases.Database(DATABASE_URL), @@ -383,13 +385,15 @@ base_ormar_config = ormar.OrmarConfig( # default sort by column id ascending class Author(ormar.Model): - ormar_config = base_ormar_config.copy() + ormar_config = base_ormar_config.copy( + tablename="authors", + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) ``` Modified -```python +```python hl_lines="9" base_ormar_config = ormar.OrmarConfig( database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData(), @@ -410,9 +414,6 @@ class Author(ormar.Model): There are two ways to create and persist the `Model` instance in the database. -!!!tip - Use `ipython` to try this from the console, since it supports `await`. - If you plan to modify the instance in the later execution of your program you can initiate your `Model` as a normal class and later await a `save()` call. ```Python hl_lines="25-26" diff --git a/docs/models/inheritance.md b/docs/models/inheritance.md index 36695bd9d..293f5d354 100644 --- a/docs/models/inheritance.md +++ b/docs/models/inheritance.md @@ -372,7 +372,7 @@ class Truck2(Car2): class Bus2(Car2): - ormar_config = base_ormar_config.copy(tablename="busses2") + ormar_config = base_ormar_config.copy(tablename="buses2") max_persons: int = ormar.Integer() ``` diff --git a/docs_src/models/docs013.py b/docs_src/models/docs013.py index fbd85efe3..2aa3958d1 100644 --- a/docs_src/models/docs013.py +++ b/docs_src/models/docs013.py @@ -7,7 +7,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) From 6b0245d62ebdf2d74ea9a11ab83f3cb0d4259e46 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 10 Mar 2024 18:25:04 +0100 Subject: [PATCH 89/95] proofread and fix the docs for models --- docs/models/inheritance.md | 8 ++-- docs/models/methods.md | 94 +++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 52 deletions(-) diff --git a/docs/models/inheritance.md b/docs/models/inheritance.md index 293f5d354..cca98ebae 100644 --- a/docs/models/inheritance.md +++ b/docs/models/inheritance.md @@ -7,7 +7,7 @@ Out of various types of ORM models inheritance `ormar` currently supports two of ## Types of inheritance -The short summary of different types of inheritance is: +The short summary of different types of inheritance: * **Mixins [SUPPORTED]** - don't subclass `ormar.Model`, just define fields that are later used on different models (like `created_date` and `updated_date` on each model), @@ -126,8 +126,6 @@ class Category(DateFieldsModel, AuditModel): The list of inherited options/settings is as follows: `metadata`, `database` and `constraints`. -Also methods decorated with `@property_field` decorator will be inherited/recognized. - Of course apart from that all fields from base classes are combined and created in the concrete table of the final Model. @@ -143,7 +141,7 @@ inheritance. Whenever you define a field with same name and new definition it will completely replace the previously defined one. -```python +```python hl_lines="28" # base class class DateFieldsModel(ormar.Model): ormar_config = OrmarConfig( @@ -324,7 +322,7 @@ Person.ormar_config.model_fields Similarly, you can inherit from Models that have ManyToMany relations declared but there is one, but substantial difference - the Through model. -Since in the future the Through model will be able to hold additional fields and now it links only two Tables +Since the Through model will be able to hold additional fields, and now it links only two Tables (`from` and `to` ones), each child that inherits the m2m relation field has to have separate Through model. diff --git a/docs/models/methods.md b/docs/models/methods.md index 13fb33e36..85f6e58e7 100644 --- a/docs/models/methods.md +++ b/docs/models/methods.md @@ -13,37 +13,37 @@ Available methods are described below. ## `pydantic` methods Note that each `ormar.Model` is also a `pydantic.BaseModel`, so all `pydantic` methods are also available on a model, -especially `model_dump()` and `json()` methods that can also accept `exclude`, `include` and other parameters. +especially `model_dump()` and `model_dump_json()` methods that can also accept `exclude`, `include` and other parameters. To read more check [pydantic][pydantic] documentation -## construct +## model_construct() -`construct` is a raw equivalent of `__init__` method used for construction of new instances. +`model_construct` is a raw equivalent of `__init__` method used for construction of new instances. -The difference is that `construct` skips validations, so it should be used when you know that data is correct and can be trusted. +The difference is that `model_construct` skips validations, so it should be used when you know that data is correct and can be trusted. The benefit of using construct is the speed of execution due to skipped validation. !!!note - Note that in contrast to `pydantic.construct` method - the `ormar` equivalent will also process the nested related models. + Note that in contrast to `pydantic.model_construct` method - the `ormar` equivalent will also process the nested related models. !!!warning - Bear in mind that due to skipped validation the `construct` method does not perform any conversions, checks etc. - So it's your responsibility to provide that data that is valid and can be consumed by the database. - - The only two things that construct still performs are: + Bear in mind that due to skipped validation the `construct` method does not perform any conversions, checks etc. + So it's your responsibility to provide that data that is valid and can be consumed by the database. + + The only two things that construct still performs are: - * Providing a `default` value for not set fields - * Initialize nested ormar models if you pass a dictionary or a primary key value + * Providing a `default` value for not set fields + * Initialize nested ormar models if you pass a dictionary or a primary key value -## dict +## model_dump() -`dict` is a method inherited from `pydantic`, yet `ormar` adds its own parameters and has some nuances when working with default values, +`model_dump` is a method inherited from `pydantic`, yet `ormar` adds its own parameters and has some nuances when working with default values, therefore it's listed here for clarity. -`dict` as the name suggests export data from model tree to dictionary. +`model_dump` as the name suggests export data from model tree to dictionary. -Explanation of dict parameters: +Explanation of model_dump parameters: ### include (`ormar` modified) @@ -55,14 +55,14 @@ Note that `pydantic` has an uncommon pattern of including/ excluding fields in l And if you want to exclude the field in all children you need to pass a `__all__` key to dictionary. You cannot exclude nested models in `Set`s in `pydantic` but you can in `ormar` -(by adding double underscore on relation name i.e. to exclude name of category for a book you cen use `exclude={"book__category__name"}`) +(by adding double underscore on relation name i.e. to exclude name of category for a book you can use `exclude={"book__category__name"}`) `ormar` does not support by index exclusion/ inclusions and accepts a simplified and more user-friendly notation. To check how you can include/exclude fields, including nested fields check out [fields](../queries/select-columns.md#fields) section that has an explanation and a lot of samples. !!!note - The fact that in `ormar` you can exclude nested models in sets, you can exclude from a whole model tree in `response_model_exclude` and `response_model_include` in fastapi! + The fact that in `ormar` you can exclude nested models in sets, you can exclude from a whole model tree in `response_model_exclude` and `response_model_include` in fastapi! ### exclude (`ormar` modified) @@ -81,7 +81,7 @@ You cannot exclude nested models in `Set`s in `pydantic` but you can in `ormar` To check how you can include/exclude fields, including nested fields check out [fields](../queries/select-columns.md#fields) section that has an explanation and a lot of samples. !!!note - The fact that in `ormar` you can exclude nested models in sets, you can exclude from a whole model tree in `response_model_exclude` and `response_model_include` in fastapi! + The fact that in `ormar` you can exclude nested models in sets, you can exclude from a whole model tree in `response_model_exclude` and `response_model_include` in fastapi! ### exclude_unset @@ -90,9 +90,9 @@ To check how you can include/exclude fields, including nested fields check out [ Flag indicates whether fields which were not explicitly set when creating the model should be excluded from the returned dictionary. !!!warning - Note that after you save data into database each field has its own value -> either provided by you, default, or `None`. - - That means that when you load the data from database, **all** fields are set, and this flag basically stop working! + Note that after you save data into database each field has its own value -> either provided by you, default, or `None`. + + That means that when you load the data from database, **all** fields are set, and this flag basically stop working! ```python class Category(ormar.Model): @@ -270,26 +270,26 @@ assert item.model_dump(exclude_through_models=True) == { ]} ``` -## json +## model_dump_json() -`json()` has exactly the same parameters as `model_dump()` so check above. +`model_dump_json()` has exactly the same parameters as `model_dump()` so check above. Of course the end result is a string with json representation and not a dictionary. -## get_pydantic +## get_pydantic() `get_pydantic(include: Union[Set, Dict] = None, exclude: Union[Set, Dict] = None)` This method allows you to generate `pydantic` models from your ormar models without you needing to retype all the fields. -Note that if you have nested models, it **will generate whole tree of pydantic models for you!** +Note that if you have nested models, it **will generate whole tree of pydantic models for you!** but in a way that prevents cyclic references issues. Moreover, you can pass `exclude` and/or `include` parameters to keep only the fields that you want to, including in nested models. That means that this way you can effortlessly create pydantic models for requests and responses in `fastapi`. !!!Note - To read more about possible excludes/includes and how to structure your exclude dictionary or set visit [fields](../queries/select-columns.md#fields) section of documentation + To read more about possible excludes/includes and how to structure your exclude dictionary or set visit [fields](../queries/select-columns.md#fields) section of documentation Given sample ormar models like follows: @@ -330,8 +330,8 @@ class Category(BaseModel): ``` !!!warning - Note that it's not a good practice to have several classes with same name in one module, as well as it would break `fastapi` docs. - Thats's why ormar adds random 3 uppercase letters to the class name. In example above it means that in reality class would be named i.e. `Category_XIP(BaseModel)`. + Note that it's not a good practice to have several classes with same name in one module, as well as it would break `fastapi` docs. + Thats's why ormar adds random 3 uppercase letters to the class name. In example above it means that in reality class would be named i.e. `Category_XIP(BaseModel)`. To exclude or include nested fields you can use dict or double underscores. @@ -351,19 +351,19 @@ class Category(BaseModel): items: Optional[List[Item]] ``` -Of course, you can use also deeply nested structures and ormar will generate it pydantic equivalent you (in a way that exclude loops). +Of course, you can use also deeply nested structures and ormar will generate it's pydantic equivalent for you (in a way that exclude loops). Note how `Item` model above does not have a reference to `Category` although in ormar the relation is bidirectional (and `ormar.Item` has `categories` field). !!!warning - Note that the generated pydantic model will inherit all **field** validators from the original `ormar` model, that includes the ormar choices validator as well as validators defined with `pydantic.validator` decorator. - - But, at the same time all root validators present on `ormar` models will **NOT** be copied to the generated pydantic model. Since root validator can operate on all fields and a user can exclude some fields during generation of pydantic model it's not safe to copy those validators. - If required, you need to redefine/ manually copy them to generated pydantic model. + Note that the generated pydantic model will inherit all **field** validators from the original `ormar` model, that includes the ormar choices validator as well as validators defined with `pydantic.validator` decorator. + + But, at the same time all root validators present on `ormar` models will **NOT** be copied to the generated pydantic model. Since root validator can operate on all fields and a user can exclude some fields during generation of pydantic model it's not safe to copy those validators. + If required, you need to redefine/ manually copy them to generated pydantic model. -## load +## load() -By default when you query a table without prefetching related models, the ormar will still construct +By default, when you query a table without prefetching related models, the ormar will still construct your related models, but populate them only with the pk value. You can load the related model by calling `load()` method. `load()` can also be used to refresh the model from the database (if it was changed by some other process). @@ -378,14 +378,14 @@ await track.album.load() track.album.name # will return 'Malibu' ``` -## load_all +## load_all() `load_all(follow: bool = False, exclude: Union[List, str, Set, Dict] = None) -> Model` Method works like `load()` but also goes through all relations of the `Model` on which the method is called, and reloads them from database. -By default the `load_all` method loads only models that are directly related (one step away) to the model on which the method is called. +By default, the `load_all` method loads only models that are directly related (one step away) to the model on which the method is called. But you can specify the `follow=True` parameter to traverse through nested models and load all of them in the relation tree. @@ -411,7 +411,7 @@ Method performs one database query so it's more efficient than nested calls to ` !!!warning All relations are cleared on `load_all()`, so if you exclude some nested models they will be empty after call. -## save +## save() `save() -> self` @@ -430,7 +430,7 @@ track = await Track.objects.get(name='The Bird') await track.save() # will raise integrity error as pk is populated ``` -## update +## update() `update(_columns: List[str] = None, **kwargs) -> self` @@ -449,7 +449,7 @@ To update only selected columns from model into the database provide a list of c In example: -```python +```python hl_lines="16" class Movie(ormar.Model): ormar_config = base_ormar_config.copy() @@ -476,9 +476,9 @@ assert terminator.year == 1984 ``` !!!warning - Note that `update()` does not refresh the instance of the Model, so if you change more columns than you pass in `_columns` list your Model instance will have different values than the database! + Note that `update()` does not refresh the instance of the Model, so if you change more columns than you pass in `_columns` list your Model instance will have different values than the database! -## upsert +## upsert() `upsert(**kwargs) -> self` @@ -497,7 +497,7 @@ await track.upsert(name='The Bird Strikes Again') # will call update as pk is al ``` -## delete +## delete() You can delete models by using `QuerySet.delete()` method or by using your model and calling `delete()` method. @@ -509,7 +509,7 @@ await track.delete() # will delete the model from database !!!tip Note that that `track` object stays the same, only record in the database is removed. -## save_related +## save_related() `save_related(follow: bool = False, save_all: bool = False, exclude=Optional[Union[Set, Dict]]) -> None` @@ -532,11 +532,11 @@ If you want to skip saving some of the relations you can pass `exclude` paramete or it can be a dictionary that can also contain nested items. !!!note - Note that `exclude` parameter in `save_related` accepts only relation fields names, so - if you pass any other fields they will be saved anyway + Note that `exclude` parameter in `save_related` accepts only relation fields names, so + if you pass any other fields they will be saved anyway !!!note - To read more about the structure of possible values passed to `exclude` check `Queryset.fields` method documentation. + To read more about the structure of possible values passed to `exclude` check `Queryset.fields` method documentation. !!!warning To avoid circular updates with `follow=True` set, `save_related` keeps a set of already visited Models on each branch of relation tree, From 8598de4f46a3a41ad642c99fc8f423206fca46c1 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 10 Mar 2024 18:40:51 +0100 Subject: [PATCH 90/95] proofread and fix the docs for fields --- docs/fields/common-parameters.md | 24 +++++-------------- docs/fields/field-types.md | 41 ++------------------------------ docs/fields/pydantic-fields.md | 2 +- 3 files changed, 9 insertions(+), 58 deletions(-) diff --git a/docs/fields/common-parameters.md b/docs/fields/common-parameters.md index 80800c191..0c05d9dfa 100644 --- a/docs/fields/common-parameters.md +++ b/docs/fields/common-parameters.md @@ -174,14 +174,14 @@ If you want to, you can apply your own type, that will be **completely** replaci So it's on you as a user to provide a type that is valid in the context of given ormar field type. !!!warning - Note that by default you should use build in arguments that are passed to underlying pydantic field. - - You can check what arguments are supported in field types section or in [pydantic](https://pydantic-docs.helpmanual.io/usage/schema/#field-customisation) docs. + Note that by default you should use build in arguments that are passed to underlying pydantic field. + + You can check what arguments are supported in field types section or in [pydantic](https://pydantic-docs.helpmanual.io/usage/schema/#field-customisation) docs. !!!danger - Setting a wrong type of pydantic field can break your model, so overwrite it only when you know what you are doing. - - As it's easy to break functionality of ormar the `overwrite_pydantic_type` argument is not available on relation fields! + Setting a wrong type of pydantic field can break your model, so overwrite it only when you know what you are doing. + + As it's easy to break functionality of ormar the `overwrite_pydantic_type` argument is not available on relation fields! ```python base_ormar_config = ormar.OrmarConfig( @@ -200,18 +200,6 @@ class OverwriteTest(ormar.Model): overwrite_pydantic_type=Optional[Json[Dict[str, int]]]) ``` -## choices - -`choices`: `Sequence` = `[]` - -A set of choices allowed to be used for given field. - -Used for data validation on pydantic side. - -Prevents insertion of value not present in the choices list. - -Used in pydantic only. - [relations]: ../relations/index.md [queries]: ../queries/index.md [pydantic]: https://pydantic-docs.helpmanual.io/usage/types/#constrained-types diff --git a/docs/fields/field-types.md b/docs/fields/field-types.md index 4cafaf2c7..9ca2dd89b 100644 --- a/docs/fields/field-types.md +++ b/docs/fields/field-types.md @@ -1,10 +1,10 @@ # Fields -There are 12 basic model field types and a special `ForeignKey` and `Many2Many` fields to establish relationships between models. +There are 12 basic model field types and a special `ForeignKey` and `ManyToMany` fields to establish relationships between models. !!!tip - For explanation of `ForeignKey` and `Many2Many` fields check [relations][relations]. + For explanation of `ForeignKey` and `ManyToMany` fields check [relations][relations]. Each of the `Fields` has assigned both `sqlalchemy` column class and python type that is used to create `pydantic` model. @@ -220,43 +220,6 @@ So which one to use depends on the backend you use and on the column/ data type * Sqlalchemy column: `sqlalchemy.Enum` * Type (used for pydantic): `Type[Enum]` -#### Choices -You can change any field into `Enum` like field by passing a `choices` list that is accepted by all Field types. - -It will add both: validation in `pydantic` model and will display available options in schema, -therefore it will be available in docs of `fastapi`. - -If you still want to use `Enum` in your application you can do this by passing a `Enum` into choices -and later pass value of given option to a given field (note that Enum is not JsonSerializable). - -```python -# note that imports and endpoints declaration -# is skipped here for brevity -from enum import Enum -class TestEnum(Enum): - val1 = 'Val1' - val2 = 'Val2' - -class TestModel(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="org") - - id: int = ormar.Integer(primary_key=True) - # pass list(Enum) to choices - enum_string: str = ormar.String(max_length=100, choices=list(TestEnum)) - -# sample payload coming to fastapi -response = client.post( - "/test_models/", - json={ - "id": 1, - # you need to refer to the value of the `Enum` option - # if called like this, alternatively just use value - # string "Val1" in this case - "enum_string": TestEnum.val1.value - }, -) - -``` [relations]: ../relations/index.md [queries]: ../queries.md diff --git a/docs/fields/pydantic-fields.md b/docs/fields/pydantic-fields.md index 800e349ee..b50380c58 100644 --- a/docs/fields/pydantic-fields.md +++ b/docs/fields/pydantic-fields.md @@ -182,4 +182,4 @@ assert test_check.pydantic_test.aa == "random" ``` !!!warning - If you do not provide a value in one of the above ways `ValidationError` will be raised on load from database. + If you do not provide a value in one of the above ways `ValidationError` will be raised on load from database. From ef6793c135cfe8fa4d358d624c8d517a48daf11c Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 10 Mar 2024 19:03:19 +0100 Subject: [PATCH 91/95] proofread and fix the docs for relations --- docs/relations/foreign-key.md | 8 ++++---- docs/relations/index.md | 6 +++--- docs/relations/many-to-many.md | 12 +++++++----- docs/relations/postponed-annotations.md | 15 +-------------- docs/relations/queryset-proxy.md | 2 +- mkdocs.yml | 4 ++-- 6 files changed, 18 insertions(+), 29 deletions(-) diff --git a/docs/relations/foreign-key.md b/docs/relations/foreign-key.md index 5860ad2dc..a51114146 100644 --- a/docs/relations/foreign-key.md +++ b/docs/relations/foreign-key.md @@ -45,7 +45,7 @@ But you cannot: * Access the related field from reverse model with `related_name` * Even if you `select_related` from reverse side of the model the returned models won't be populated in reversed instance (the join is not prevented so you still can `filter` and `order_by` over the relation) -* The relation won't be populated in `model_dump()` and `json()` +* The relation won't be populated in `model_dump()` and `model_dump_json()` * You cannot pass the nested related objects when populating from dictionary or json (also through `fastapi`). It will be either ignored or error will be raised depending on `extra` setting in pydantic `Config`. Example: @@ -110,7 +110,7 @@ assert department.courses[0] == course !!!warning If you want to add child model on related model the primary key value for parent model **has to exist in database**. - Otherwise ormar will raise RelationshipInstanceError as it cannot set child's ForeignKey column value + Otherwise ormar will raise `RelationshipInstanceError` as it cannot set child's ForeignKey column value if parent model has no primary key value. That means that in example above the department has to be saved before you can call `department.courses.add()`. @@ -149,7 +149,7 @@ await department.courses.remove(course, keep_reversed=False) Removal of all related models in one call. -Like remove by default `clear()` nulls the ForeigKey column on child model (all, not matter if they are loaded or not). +Like with remove, by default, `clear()` nulls the ForeigKey column on child model (all, not matter if they are loaded or not). ```python # nulls department column on all courses related to this department @@ -171,7 +171,7 @@ To read which methods of QuerySet are available read below [querysetproxy][query ## related_name -But you can overwrite this name by providing `related_name` parameter like below: +You can overwrite related model field name by providing `related_name` parameter like below: ```Python hl_lines="27-29 35" --8<-- "../docs_src/fields/docs002.py" diff --git a/docs/relations/index.md b/docs/relations/index.md index 979e766e5..a864bd2e5 100644 --- a/docs/relations/index.md +++ b/docs/relations/index.md @@ -26,7 +26,7 @@ The definition of one-to-many relation also uses `ForeignKey`, and it's register So in relation to example above. -```Python hl_lines="8" +```Python hl_lines="7-8" class Department(ormar.Model): ormar_config = base_ormar_config.copy() @@ -50,7 +50,7 @@ class Department(ormar.Model): To define many-to-many relation use `ManyToMany` field. -```python hl_lines="18" +```python hl_lines="19" class Category(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, @@ -91,7 +91,7 @@ side of the current query for m2m models. So if you query from model `A` to model `B`, only model `B` has through field exposed. Which kind of make sense, since it's a one through model/field for each of related models. -```python hl_lines="12-20" +```python hl_lines="12-21" class Category(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, diff --git a/docs/relations/many-to-many.md b/docs/relations/many-to-many.md index de9bc108e..399709055 100644 --- a/docs/relations/many-to-many.md +++ b/docs/relations/many-to-many.md @@ -24,9 +24,9 @@ news = await Category.objects.create(name="News") `ForeignKey` fields are automatically registering reverse side of the relation. -By default it's child (source) `Model` name + s, like courses in snippet below: +By default it's child (source) `Model` name + s, like `posts` in snippet below: -```python +```python hl_lines="25-26" class Category(ormar.Model): ormar_config = base_ormar_config.copy(tablename="categories") @@ -79,12 +79,14 @@ categories: Optional[Union[Category, List[Category]]] = ormar.ManyToMany( If you are sure you don't want the reverse relation you can use `skip_reverse=True` flag of the `ManyToMany`. - If you set `skip_reverse` flag internally the field is still registered on the other - side of the relationship so you can: +If you set `skip_reverse` flag internally the field is still registered on the other +side of the relationship so you can: + * `filter` by related models fields from reverse model * `order_by` by related models fields from reverse model - But you cannot: +But you cannot: + * access the related field from reverse model with `related_name` * even if you `select_related` from reverse side of the model the returned models won't be populated in reversed instance (the join is not prevented so you still can `filter` and `order_by` over the relation) * the relation won't be populated in `model_dump()` and `json()` diff --git a/docs/relations/postponed-annotations.md b/docs/relations/postponed-annotations.md index 5907f8a34..b5b04d44c 100644 --- a/docs/relations/postponed-annotations.md +++ b/docs/relations/postponed-annotations.md @@ -14,21 +14,8 @@ First, you need to import the required ref from typing. from typing import ForwardRef ``` -But note that before python 3.7 it used to be internal, so for python <= 3.6 you need - -```python -from typing import _ForwardRef as ForwardRef -``` - -or since `pydantic` is required by `ormar` it can handle this switch for you. -In that case you can simply import ForwardRef from pydantic regardless of your python version. - -```python -from pydantic.typing import ForwardRef -``` - Now we need a sample model and a reference to the same model, -which will be used to creat a self referencing relation. +which will be used to create a self referencing relation. ```python # create the forwardref to model Person diff --git a/docs/relations/queryset-proxy.md b/docs/relations/queryset-proxy.md index 90c89fbfb..097fc304d 100644 --- a/docs/relations/queryset-proxy.md +++ b/docs/relations/queryset-proxy.md @@ -58,7 +58,7 @@ assert post.categories[0] == news `get_or_create(_defaults: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[Model, bool]` -Tries to get a row meeting the criteria and if NoMatch exception is raised it creates a new one with given kwargs and _defaults. +Tries to get a row meeting the criteria and if `NoMatch` exception is raised it creates a new one with given kwargs and _defaults. !!!tip Read more in queries documentation [get_or_create][get_or_create] diff --git a/mkdocs.yml b/mkdocs.yml index c50401a60..e5052e5bf 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,10 +16,10 @@ nav: - Pydantic only fields: fields/pydantic-fields.md - Fields encryption: fields/encryption.md - Relations: - - relations/index.md - - relations/postponed-annotations.md + - Relation types: relations/index.md - relations/foreign-key.md - relations/many-to-many.md + - relations/postponed-annotations.md - relations/queryset-proxy.md - Queries: - queries/index.md From c569870431a8bcf990294268399f90b57176aa5f Mon Sep 17 00:00:00 2001 From: collerek Date: Sat, 16 Mar 2024 20:21:54 +0100 Subject: [PATCH 92/95] proofread and fix rest of the docs, add release notes for 0.20 --- docs/fastapi/index.md | 6 +- docs/fastapi/requests.md | 12 +- docs/fastapi/response.md | 34 +- docs/queries/aggregations.md | 12 +- docs/queries/create.md | 15 +- docs/queries/filter-and-sort.md | 2 +- docs/queries/joins-and-subqueries.md | 8 +- docs/queries/pagination-and-rows-number.md | 18 +- docs/queries/read.md | 6 +- docs/queries/select-columns.md | 249 ++++---- docs/releases.md | 668 +++++++++++++++------ docs/signals.md | 8 +- docs_src/queries/docs001.py | 3 +- docs_src/queries/docs002.py | 3 +- docs_src/queries/docs003.py | 3 +- docs_src/queries/docs004.py | 3 +- docs_src/queries/docs005.py | 3 +- docs_src/queries/docs006.py | 3 +- docs_src/queries/docs007.py | 3 +- docs_src/queries/docs008.py | 3 +- docs_src/queries/docs009.py | 3 +- docs_src/select_columns/__init__.py | 0 docs_src/select_columns/docs001.py | 63 ++ 23 files changed, 782 insertions(+), 346 deletions(-) create mode 100644 docs_src/select_columns/__init__.py create mode 100644 docs_src/select_columns/docs001.py diff --git a/docs/fastapi/index.md b/docs/fastapi/index.md index 4807a0c18..14cadc036 100644 --- a/docs/fastapi/index.md +++ b/docs/fastapi/index.md @@ -16,13 +16,13 @@ Here you can find a very simple sample application code. It's divided into subsections for clarity. !!!note - If you want to read more on how you can use ormar models in fastapi requests and - responses check the [responses](response.md) and [requests](requests.md) documentation. + If you want to read more on how you can use ormar models in fastapi requests and + responses check the [responses](response.md) and [requests](requests.md) documentation. ## Quick Start !!!note - Note that you can find the full quick start script in the [github](https://github.com/collerek/ormar) repo under examples. + Note that you can find the full quick start script in the [github](https://github.com/collerek/ormar) repo under examples. ### Imports and initialization diff --git a/docs/fastapi/requests.md b/docs/fastapi/requests.md index 181b715f5..78a7ad553 100644 --- a/docs/fastapi/requests.md +++ b/docs/fastapi/requests.md @@ -44,8 +44,8 @@ In above example fields `id` (is an `autoincrement` `Integer`), `first_name` ( h If the field is nullable you don't have to include it in payload during creation as well as in response, so given example above you can: !!!Warning - Note that although you do not have to pass the optional field, you still **can** do it. - And if someone will pass a value it will be used later unless you take measures to prevent it. + Note that although you do not have to pass the optional field, you still **can** do it. + And if someone will pass a value it will be used later unless you take measures to prevent it. ```python # note that app is an FastApi app @@ -72,14 +72,14 @@ async def create_user3(user: RequestUser): # use the generated model here ``` !!!Note - To see more examples and read more visit [get_pydantic](../models/methods.md#get_pydantic) part of the documentation. + To see more examples and read more visit [get_pydantic](../models/methods.md#get_pydantic) part of the documentation. !!!Warning - The `get_pydantic` method generates all models in a tree of nested models according to an algorithm that allows to avoid loops in models (same algorithm that is used in `model_dump()`, `select_all()` etc.) + The `get_pydantic` method generates all models in a tree of nested models according to an algorithm that allows to avoid loops in models (same algorithm that is used in `model_dump()`, `select_all()` etc.) - That means that nested models won't have reference to parent model (by default ormar relation is bidirectional). + That means that nested models won't have reference to parent model (by default ormar relation is bidirectional). - Note also that if given model exists in a tree more than once it will be doubled in pydantic models (each occurrence will have separate own model). That way you can exclude/include different fields on different leafs of the tree. + Note also that if given model exists in a tree more than once it will be doubled in pydantic models (each occurrence will have separate own model). That way you can exclude/include different fields on different leafs of the tree. #### Mypy and type checking diff --git a/docs/fastapi/response.md b/docs/fastapi/response.md index 3949bfeb9..21d6f2a4f 100644 --- a/docs/fastapi/response.md +++ b/docs/fastapi/response.md @@ -52,9 +52,9 @@ async def create_user(user: User): # here we use ormar.Model in request paramet That means that if you do not pass i.e. `first_name` in request it will validate correctly (as field is optional), save in the database and return the saved record without this field (which will also pass validation). !!!Note - Note that although you do not pass the **field value**, the **field itself** is still present in the `response_model` that means it **will be present in response data** and set to `None`. + Note that although you do not pass the **field value**, the **field itself** is still present in the `response_model` that means it **will be present in response data** and set to `None`. - If you want to fully exclude the field from the result read on. + If you want to fully exclude the field from the result read on. ### FastApi `response_model_exclude` @@ -63,7 +63,7 @@ Fastapi has `response_model_exclude` that accepts a set (or a list) of field nam That has it's limitation as `ormar` and `pydantic` accepts also dictionaries in which you can set exclude/include columns also on nested models (more on this below) !!!Warning - Note that you cannot exclude required fields when using `response_model` as it will fail during validation. + Note that you cannot exclude required fields when using `response_model` as it will fail during validation. ```python @app.post("/users/", response_model=User, response_model_exclude={"password"}) @@ -98,9 +98,9 @@ with client as client: ``` !!!Note - Note how in above example `password` field is fully gone from the response data. + Note how in above example `password` field is fully gone from the response data. - Note that you can use this method only for non-required fields. + Note that you can use this method only for non-required fields. #### Nested models excludes @@ -148,11 +148,11 @@ Note that you can go in deeper models with double underscore, and if you want to In example `response_model_exclude={"category__priority", "category__other_field", category__nested_model__nested_model_field}` etc. !!!Note - To read more about possible excludes and how to structure your exclude dictionary or set visit [fields](../queries/select-columns.md#fields) section of documentation + To read more about possible excludes and how to structure your exclude dictionary or set visit [fields](../queries/select-columns.md#fields) section of documentation !!!Note - Note that apart from `response_model_exclude` parameter `fastapi` supports also other parameters inherited from `pydantic`. - All of them works also with ormar, but can have some nuances so best to read [dict](../models/methods.md#dict) part of the documentation. + Note that apart from `response_model_exclude` parameter `fastapi` supports also other parameters inherited from `pydantic`. + All of them works also with ormar, but can have some nuances so best to read [dict](../models/methods.md#dict) part of the documentation. ### Exclude in `Model.model_dump()` @@ -161,7 +161,7 @@ Alternatively you can just return a dict from `ormar.Model` and use . Like this you can also set exclude/include as dict and exclude fields on nested models too. !!!Warning - Not using a `response_model` will cause api documentation having no response example and schema since in theory response can have any format. + Not using a `response_model` will cause api documentation having no response example and schema since in theory response can have any format. ```python @app.post("/users2/", response_model=User) @@ -172,7 +172,7 @@ async def create_user2(user: User): ``` !!!Note - Note that above example will nullify the password field even if you pass it in request, but the **field will be still there** as it's part of the response schema, the value will be set to `None`. + Note that above example will nullify the password field even if you pass it in request, but the **field will be still there** as it's part of the response schema, the value will be set to `None`. If you want to fully exclude the field with this approach simply don't use `response_model` and exclude in Model's model_dump() @@ -180,7 +180,7 @@ Alternatively you can just return a dict from ormar model. Like this you can also set exclude/include as dict and exclude fields on nested models. !!!Note - In theory you loose validation of response here but since you operate on `ormar.Models` the response data have already been validated after db query (as ormar model is pydantic model). + In theory you loose validation of response here but since you operate on `ormar.Models` the response data have already been validated after db query (as ormar model is pydantic model). So if you skip `response_model` altogether you can do something like this: @@ -192,9 +192,9 @@ async def create_user4(user: User): ``` !!!Note - Note that when you skip the response_model you can now **exclude also required fields** as the response is no longer validated after being returned. + Note that when you skip the response_model you can now **exclude also required fields** as the response is no longer validated after being returned. - The cost of this solution is that you loose also api documentation as response schema in unknown from fastapi perspective. + The cost of this solution is that you loose also api documentation as response schema in unknown from fastapi perspective. ### Generate `pydantic` model from `ormar.Model` @@ -211,14 +211,14 @@ async def create_user3(user: User): ``` !!!Note - To see more examples and read more visit [get_pydantic](../models/methods.md#get_pydantic) part of the documentation. + To see more examples and read more visit [get_pydantic](../models/methods.md#get_pydantic) part of the documentation. !!!Warning - The `get_pydantic` method generates all models in a tree of nested models according to an algorithm that allows to avoid loops in models (same algorithm that is used in `model_dump()`, `select_all()` etc.) + The `get_pydantic` method generates all models in a tree of nested models according to an algorithm that allows to avoid loops in models (same algorithm that is used in `model_dump()`, `select_all()` etc.) - That means that nested models won't have reference to parent model (by default ormar relation is bidirectional). + That means that nested models won't have reference to parent model (by default ormar relation is bidirectional). - Note also that if given model exists in a tree more than once it will be doubled in pydantic models (each occurrence will have separate own model). That way you can exclude/include different fields on different leafs of the tree. + Note also that if given model exists in a tree more than once it will be doubled in pydantic models (each occurrence will have separate own model). That way you can exclude/include different fields on different leafs of the tree. ### Separate `pydantic` model diff --git a/docs/queries/aggregations.md b/docs/queries/aggregations.md index 6294754ff..74b8ec0d6 100644 --- a/docs/queries/aggregations.md +++ b/docs/queries/aggregations.md @@ -32,7 +32,11 @@ the count will be the total number of rows returned ```python class Book(ormar.Model): - ormar_config = base_ormar_config.copy() + ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + tablename="book" + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) @@ -57,7 +61,11 @@ Returns a bool value to confirm if there are rows matching the given criteria (a ```python class Book(ormar.Model): - ormar_config = base_ormar_config.copy() + ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + tablename="book" + ) id: int = ormar.Integer(primary_key=True) title: str = ormar.String(max_length=200) diff --git a/docs/queries/create.md b/docs/queries/create.md index b10962f3a..e0dbce2cb 100644 --- a/docs/queries/create.md +++ b/docs/queries/create.md @@ -30,7 +30,12 @@ The allowed kwargs are `Model` fields names and proper value types. ```python class Album(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="album") + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="album" + ) + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) @@ -49,7 +54,7 @@ await malibu.save() ``` !!!tip - Check other `Model` methods in [models][models] + Check other `Model` methods in [models][models] ## get_or_create @@ -65,7 +70,11 @@ i.e. `get_or_create(_defaults: {"title": "I win"}, title="never used")` will alw ```python class Album(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="album") + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="album" + ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) diff --git a/docs/queries/filter-and-sort.md b/docs/queries/filter-and-sort.md index 1888a6b17..72a4a1d2f 100644 --- a/docs/queries/filter-and-sort.md +++ b/docs/queries/filter-and-sort.md @@ -704,7 +704,7 @@ Ordering in sql will be applied in order of names you provide in order_by. Given sample Models like following: ```python ---8 < -- "../../docs_src/queries/docs007.py" +--8<-- "../docs_src/queries/docs007.py" ``` To order by main model field just provide a field name diff --git a/docs/queries/joins-and-subqueries.md b/docs/queries/joins-and-subqueries.md index bc0b0a06a..85a092e04 100644 --- a/docs/queries/joins-and-subqueries.md +++ b/docs/queries/joins-and-subqueries.md @@ -390,12 +390,12 @@ might be faster despite it needs to perform three separate queries instead of on #### Memory -`ormar` is a mini ORM meaning that it does not keep a registry of already loaded models. +`ormar` is does not keep a registry of already loaded models. That means that in `select_related` example above you will always have 10 000 Models A, 30 000 Models B -(even if the unique number of rows in db is 3 - processing of `select_related` spawns ** -new** child models for each parent model). And 60 000 Models C. +(even if the unique number of rows in db is 3 - processing of `select_related` spawns +**new** child models for each parent model). And 60 000 Models C. If the same Model B is shared by rows 1, 10, 100 etc. and you update one of those, the rest of rows that share the same child will **not** be updated on the spot. If you @@ -429,7 +429,7 @@ that `select_related` will use more memory as each child is instantiated as a ne ```python # will return False (note that id is a python `builtin` function not ormar one). - id(row1.child1) == (ro100.child1) + id(row1.child1) == id(ro100.child1) # from above - will also return False id(model1) == id(model2) diff --git a/docs/queries/pagination-and-rows-number.md b/docs/queries/pagination-and-rows-number.md index c810ac6cb..be658405b 100644 --- a/docs/queries/pagination-and-rows-number.md +++ b/docs/queries/pagination-and-rows-number.md @@ -22,7 +22,11 @@ Combines the `offset` and `limit` methods based on page number and size ```python class Track(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="track") + ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + tablename="track" + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -49,7 +53,11 @@ use the `limit_raw_sql` parameter flag, and set it to `True`. ```python class Track(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="track") + ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + tablename="track" + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) @@ -80,7 +88,11 @@ use the `limit_raw_sql` parameter flag, and set it to `True`. ```python class Track(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="track") + ormar.OrmarConfig( + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), + tablename="track" + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) diff --git a/docs/queries/read.md b/docs/queries/read.md index 295234b14..e5d7a9fa8 100644 --- a/docs/queries/read.md +++ b/docs/queries/read.md @@ -31,7 +31,11 @@ Passing a criteria is actually calling filter(*args, **kwargs) method described ```python class Track(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="track") + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="track" + ) id: int = ormar.Integer(primary_key=True) album: Optional[Album] = ormar.ForeignKey(Album) diff --git a/docs/queries/select-columns.md b/docs/queries/select-columns.md index 2185c4b27..206cc7ee6 100644 --- a/docs/queries/select-columns.md +++ b/docs/queries/select-columns.md @@ -24,46 +24,7 @@ With `fields()` you can select subset of model columns to limit the data load. Given a sample data like following: ```python -import databases -import sqlalchemy - -import ormar -from tests.settings import DATABASE_URL - -database = databases.Database(DATABASE_URL, force_rollback=True) -metadata = sqlalchemy.MetaData() - - -class Company(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="companies") - - id: int = ormar.Integer(primary_key=True) - name: str = ormar.String(max_length=100) - founded: int = ormar.Integer(nullable=True) - - -class Car(ormar.Model): - ormar_config = base_ormar_config.copy() - - id: int = ormar.Integer(primary_key=True) - manufacturer = ormar.ForeignKey(Company) - name: str = ormar.String(max_length=100) - year: int = ormar.Integer(nullable=True) - gearbox_type: str = ormar.String(max_length=20, nullable=True) - gears: int = ormar.Integer(nullable=True) - aircon_type: str = ormar.String(max_length=20, nullable=True) - - -# build some sample data -toyota = await Company.objects.create(name="Toyota", founded=1937) -await Car.objects.create(manufacturer=toyota, name="Corolla", year=2020, gearbox_type='Manual', gears=5, - aircon_type='Manual') -await Car.objects.create(manufacturer=toyota, name="Yaris", year=2019, gearbox_type='Manual', gears=5, - aircon_type='Manual') -await Car.objects.create(manufacturer=toyota, name="Supreme", year=2020, gearbox_type='Auto', gears=6, - aircon_type='Auto') - - +--8<-- "../docs_src/select_columns/docs001.py" ``` You can select specified fields by passing a `str, List[str], Set[str] or dict` with @@ -72,8 +33,13 @@ nested definition. To include related models use notation `{related_name}__{column}[__{optional_next} etc.]`. -```python hl_lines="1" -all_cars = await Car.objects.select_related('manufacturer').fields(['id', 'name', 'manufacturer__name']).all() +```python hl_lines="1-6" +all_cars = await ( + Car.objects + .select_related('manufacturer') + .fields(['id', 'name', 'manufacturer__name']) + .all() +) for car in all_cars: # excluded columns will yield None assert all(getattr(car, x) is None for x in ['year', 'gearbox_type', 'gears', 'aircon_type']) @@ -91,9 +57,14 @@ for those models in fields - implies a list of all fields for those nested models. -```python hl_lines="1" -all_cars = await Car.objects.select_related('manufacturer').fields('id').fields( - ['name']).all() +```python hl_lines="1-7" +all_cars = await ( + Car.objects + .select_related('manufacturer') + .fields('id') + .fields(['name']) + .all() +) # all fields from company model are selected assert all_cars[0].manufacturer.name == 'Toyota' assert all_cars[0].manufacturer.founded == 1937 @@ -109,8 +80,12 @@ assert all_cars[0].manufacturer.founded == 1937 You cannot exclude mandatory model columns - `manufacturer__name` in this example. ```python -await Car.objects.select_related('manufacturer').fields( - ['id', 'name', 'manufacturer__founded']).all() +await ( + Car.objects + .select_related('manufacturer') + .fields(['id', 'name', 'manufacturer__founded']) + .all() +) # will raise pydantic ValidationError as company.name is required ``` @@ -132,38 +107,71 @@ Below you can see examples that are equivalent: ```python # 1. like in example above -await Car.objects.select_related('manufacturer').fields(['id', 'name', 'manufacturer__name']).all() +await ( + Car.objects + .select_related('manufacturer') + .fields(['id', 'name', 'manufacturer__name']) + .all() +) # 2. to mark a field as required use ellipsis -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': { - 'name': ...} - }).all() +await ( + Car.objects + .select_related('manufacturer') + .fields({'id': ..., + 'name': ..., + 'manufacturer': { + 'name': ... + } + }) + .all() +) # 3. to include whole nested model use ellipsis -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': ... - }).all() +await ( + Car.objects + .select_related('manufacturer') + .fields({'id': ..., + 'name': ..., + 'manufacturer': ... + }) + .all() +) -# 4. to specify fields at last nesting level you can also use set - equivalent to 2. above -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': {'name'} - }).all() +# 4. to specify fields at last nesting level +# you can also use set - equivalent to 2. above +await ( + Car.objects + .select_related('manufacturer') + .fields({'id': ..., + 'name': ..., + 'manufacturer': {'name'} + }) + .all() +) # 5. of course set can have multiple fields -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': {'name', 'founded'} - }).all() +await ( + Car.objects + .select_related('manufacturer') + .fields({'id': ..., + 'name': ..., + 'manufacturer': {'name', 'founded'} + }) + .all() +) -# 6. you can include all nested fields but it will be equivalent of 3. above which is shorter -await Car.objects.select_related('manufacturer').fields({'id': ..., - 'name': ..., - 'manufacturer': {'id', 'name', 'founded'} - }).all() +# 6. you can include all nested fields, +# but it will be equivalent of 3. above which is shorter +await ( + Car.objects + .select_related('manufacturer') + .fields({'id': ..., + 'name': ..., + 'manufacturer': {'id', 'name', 'founded'} + }) + .all() +) ``` @@ -195,70 +203,65 @@ exclude fields from whole hierarchy. Below you can find few simple examples: -```python hl_lines="47 48 60 61 67" -import databases -import sqlalchemy - -import ormar -from tests.settings import DATABASE_URL +```python +--8<-- "../docs_src/select_columns/docs001.py" +``` -base_ormar_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL, force_rollback=True), - metadata=sqlalchemy.MetaData(), +```python +# select manufacturer but only name, +# to include related models use notation {model_name}__{column} +all_cars = await ( + Car.objects + .select_related('manufacturer') + .exclude_fields([ + 'year', + 'gearbox_type', + 'gears', + 'aircon_type', + 'company__founded' + ]) + .all() ) - - -class Company(ormar.Model): - ormar_config = base_ormar_config.copy(tablename="companies") - - id: int = ormar.Integer(primary_key=True) - name: str = ormar.String(max_length=100) - founded: int = ormar.Integer(nullable=True) - - -class Car(ormar.Model): - ormar_config = base_ormar_config.copy() - - id: int = ormar.Integer(primary_key=True) - manufacturer = ormar.ForeignKey(Company) - name: str = ormar.String(max_length=100) - year: int = ormar.Integer(nullable=True) - gearbox_type: str = ormar.String(max_length=20, nullable=True) - gears: int = ormar.Integer(nullable=True) - aircon_type: str = ormar.String(max_length=20, nullable=True) - - -# build some sample data -toyota = await Company.objects.create(name="Toyota", founded=1937) -await Car.objects.create(manufacturer=toyota, name="Corolla", year=2020, gearbox_type='Manual', gears=5, - aircon_type='Manual') -await Car.objects.create(manufacturer=toyota, name="Yaris", year=2019, gearbox_type='Manual', gears=5, - aircon_type='Manual') -await Car.objects.create(manufacturer=toyota, name="Supreme", year=2020, gearbox_type='Auto', gears=6, - aircon_type='Auto') - -# select manufacturer but only name - to include related models use notation {model_name}__{column} -all_cars = await Car.objects.select_related('manufacturer').exclude_fields( - ['year', 'gearbox_type', 'gears', 'aircon_type', 'company__founded']).all() for car in all_cars: # excluded columns will yield None - assert all(getattr(car, x) is None for x in ['year', 'gearbox_type', 'gears', 'aircon_type']) - # included column on related models will be available, pk column is always included + assert all(getattr(car, x) is None + for x in [ + 'year', + 'gearbox_type', + 'gears', + 'aircon_type' + ]) + # included column on related models will be available, + # pk column is always included # even if you do not include it in fields list assert car.manufacturer.name == 'Toyota' - # also in the nested related models - you cannot exclude pk - it's always auto added + # also in the nested related models, + # you cannot exclude pk - it's always auto added assert car.manufacturer.founded is None -# fields() can be called several times, building up the columns to select -# models selected in select_related but with no columns in fields list implies all fields -all_cars = await Car.objects.select_related('manufacturer').exclude_fields('year').exclude_fields( - ['gear', 'gearbox_type']).all() +# fields() can be called several times, +# building up the columns to select +# models included in select_related +# but with no columns in fields list implies all fields +all_cars = await ( + Car.objects + .select_related('manufacturer') + .exclude_fields('year') + .exclude_fields(['gear', 'gearbox_type']) + .all() +) # all fields from company model are selected assert all_cars[0].manufacturer.name == 'Toyota' assert all_cars[0].manufacturer.founded == 1937 -# cannot exclude mandatory model columns - company__name in this example - note usage of dict/set this time -await Car.objects.select_related('manufacturer').exclude_fields([{'company': {'name'}}]).all() +# cannot exclude mandatory model columns, +# company__name in this example - note usage of dict/set this time +await ( + Car.objects + .select_related('manufacturer') + .exclude_fields([{'company': {'name'}}]) + .all() +) # will raise pydantic ValidationError as company.name is required ``` diff --git a/docs/releases.md b/docs/releases.md index 748801bb7..7c44d7f26 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -1,224 +1,552 @@ -# 0.12.2 +# Release notes -## ✨ Features +## 0.20.0 + +### ✨ Breaking changes +* `ormar` Model configuration + + Instead of defining a `Meta` class now each of the ormar models require an ormar_config parameter that is an instance of the `OrmarConfig` class. + Note that the attribute must be named `ormar_config` and be an instance of the config class. + + ```python + import databases + import ormar + import sqlalchemy + + database = databases.Database("sqlite:///db.sqlite") + metadata = sqlalchemy.MetaData() + + # ormar < 0.20 + class Album(ormar.Model): + class Meta: + database = database + metadata = metadata + tablename = "albums" + + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + + # ormar >= 0.20 + class AlbumV20(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="albums_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + ``` + +* `OrmarConfig` api/ parameters + + The `ormar_config` expose the same set of settings as `Meta` class used to provide. + That means that you can use any of the following parameters initializing the config: + + ```python + metadata: Optional[sqlalchemy.MetaData] + database: Optional[databases.Database] + engine: Optional[sqlalchemy.engine.Engine] + tablename: Optional[str] + order_by: Optional[List[str]] + abstract: bool + exclude_parent_fields: Optional[List[str]] + queryset_class: Type[QuerySet] + extra: Extra + constraints: Optional[List[ColumnCollectionConstraint]] + ``` + +* `BaseMeta` equivalent - best practice + + Note that to reduce the duplication of code and ease of development it's still recommended to create a base config and provide each of the models with a copy. + OrmarConfig provides a convenient `copy` method for that purpose. + + The `copy` method accepts the same parameters as `OrmarConfig` init, so you can overwrite if needed, but by default it will return already existing attributes, except for: `tablename`, `order_by` and `constraints` which by default are cleared. + + ```python hl_lines="5-8 11 20" + import databases + import ormar + import sqlalchemy + + base_ormar_config = ormar.OrmarConfig( + database=databases.Database("sqlite:///db.sqlite"), + metadata=sqlalchemy.MetaData() + ) + + class AlbumV20(ormar.Model): + ormar_config = base_ormar_config.copy( + tablename="albums_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + + + class TrackV20(ormar.Model): + ormar_config = base_ormar_config.copy( + tablename="tracks_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + ``` + +* `choices` Field parameter is no longer supported. + + Before version 0.20 you could provide `choices` parameter to any existing ormar Field to limit the accepted values. + This functionality was dropped, and you should use `ormar.Enum` field that was designed for this purpose. + If you want to keep the database field type (i.e. an Integer field) you can always write a custom validator. + + ```python + import databases + import ormar + import sqlalchemy + + database = databases.Database("sqlite:///db.sqlite") + metadata = sqlalchemy.MetaData() + + # ormar < 0.20 + class Artist(ormar.Model): + class Meta: + database = database + metadata = metadata + + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + country: str = ormar.String(default=False, max_length=50, choices=["UK", "US", "Vietnam", "Colombia"]) + + # ormar >= 0.20 + from enum import Enum + + class Country(str, Enum): + UK = "UK" + US = "US" + VIETNAM = "Vietnam" + COLOMBIA = "Colombia" + + class ArtistV20(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="artists_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + country: Country = ormar.Enum(enum_class=Country) + ``` + + +* `pydantic_only` Field parameter is no longer supported + + `pydantic_only` fields were already deprecated and are removed in v 0.20. Ormar allows defining pydantic fields as in ordinary pydantic model. + + ```python + import databases + import ormar + import sqlalchemy + + database = databases.Database("sqlite:///db.sqlite") + metadata = sqlalchemy.MetaData() + + # ormar < 0.20 + class Dish(ormar.Model): + class Meta: + database = database + metadata = metadata + tablename = "dishes" + + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + cook: str = ormar.String(max_length=40, pydantic_only=True, default="sam") + + # ormar >= 0.20 + class DishV20(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="dishes_v20" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + cook: str = "sam" # this is normal pydantic field + ``` + +* `property_field` decorator is no longer supported + + `property_field` decorator was used to provide a way to pass calculated fields that were included in dictionary/ serialized json representation of the model. + Version 2.X of pydantic introduced such a possibility, so you should now switch to the one native to the pydantic. + + ```python + import databases + import ormar + import sqlalchemy + import pydantic + + database = databases.Database("sqlite:///db.sqlite") + metadata = sqlalchemy.MetaData() + + # ormar < 0.20 + class Employee(ormar.Model): + class Meta: + database = database + metadata = metadata + + + id: int = ormar.Integer(primary_key=True) + first_name: str = ormar.String(max_length=100) + last_name: str = ormar.String(max_length=100) + + @ormar.property_field() + def full_name(self) -> str: + return f"{self.first_name} {self.last_name}" + + # ormar >= 0.20 + class EmployeeV20(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + ) + + id: int = ormar.Integer(primary_key=True) + first_name: str = ormar.String(max_length=100) + last_name: str = ormar.String(max_length=100) + + @pydantic.computed_field() + def full_name(self) -> str: + return f"{self.first_name} {self.last_name}" + ``` + +* Deprecated methods + + All methods listed below are deprecated and will be removed in version 0.30 of `ormar`. + + * `dict()` becomes the `model_dump()` + + ```python + import databases + import ormar + import sqlalchemy + + database = databases.Database("sqlite:///db.sqlite") + metadata = sqlalchemy.MetaData() + + class Album(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="albums" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + + album = Album(name="Dark Side of the Moon") + + # ormar < 0.20 + album_dict = album.dict() + + # ormar >= 0.20 + new_album_dict = album.model_dump() + ``` + + Note that parameters remain the same i.e. `include`, `exclude` etc. + + * `json()` becomes the `model_dump_json()` + + ```python + import databases + import ormar + import sqlalchemy + + database = databases.Database("sqlite:///db.sqlite") + metadata = sqlalchemy.MetaData() + + class Album(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="albums" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + + album = Album(name="Dark Side of the Moon") + + # ormar < 0.20 + album_json= album.json() + + # ormar >= 0.20 + new_album_dict = album.model_dump_json() + ``` + + Note that parameters remain the same i.e. `include`, `exclude` etc. + + * `construct()` becomes the `model_construct()` + + ```python + import databases + import ormar + import sqlalchemy + + database = databases.Database("sqlite:///db.sqlite") + metadata = sqlalchemy.MetaData() + + class Album(ormar.Model): + ormar_config = ormar.OrmarConfig( + database=database, + metadata=metadata, + tablename="albums" + ) + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + favorite: bool = ormar.Boolean(default=False) + + params = { + "name": "Dark Side of the Moon", + "favorite": True, + } + # ormar < 0.20 + album = Album.construct(**params) + + # ormar >= 0.20 + album = Album.model_construct(**params) + ``` + + To read more about construct please refer to `pydantic` documentation. + + +##0.12.2 + +###✨ Features * Bump support for `FastAPI` up to the newest version (0.97.0) [#1110](https://github.com/collerek/ormar/pull/1110) * Add support and tests for `Python 3.11` [#1110](https://github.com/collerek/ormar/pull/1110) -# 0.12.1 +##0.12.1 -## ✨ Features +###✨ Features * Massive performance improvements in area of loading the models due to recursive loads and caching of the models and related models. (by @erichaydel - thanks!) [#853](https://github.com/collerek/ormar/pull/948) -## 💬 Internals +###💬 Internals * Benchmarks for comparing performance effect of implemented changes in regard of trends (again, by @erichaydel - thanks!) [#853](https://github.com/collerek/ormar/pull/948) -# 0.12.0 +##0.12.0 -## ✨ Breaking Changes +###✨ Breaking Changes * `Queryset.bulk_create` will now raise `ModelListEmptyError` on empty list of models (by @ponytailer - thanks!) [#853](https://github.com/collerek/ormar/pull/853) -## ✨ Features +###✨ Features * `Model.upsert()` now handles a flag `__force_save__`: `bool` that allow upserting the models regardless of the fact if they have primary key set or not. Note that setting this flag will cause two queries for each upserted model -> `get` to check if model exists and later `update/insert` accordingly. [#889](https://github.com/collerek/ormar/pull/853) -## 🐛 Fixes +###🐛 Fixes * Fix for empty relations breaking `construct` method (by @Abdeldjalil-H - thanks!) [#870](https://github.com/collerek/ormar/issues/870) * Fix save related not saving models with already set pks (including uuid) [#885](https://github.com/collerek/ormar/issues/885) * Fix for wrong relations exclusions depending on the order of exclusions [#779](https://github.com/collerek/ormar/issues/779) * Fix `property_fields` not being inherited properly [#774](https://github.com/collerek/ormar/issues/774) -# 0.11.3 +##0.11.3 -## ✨ Features +###✨ Features * Document `onupdate` and `ondelete` referential actions in `ForeignKey` and provide `ReferentialAction` enum to specify the behavior of the relationship (by @SepehrBazyar - thanks!) [#724](https://github.com/collerek/ormar/issues/724) * Add `CheckColumn` to supported constraints in models Meta (by @SepehrBazyar - thanks!) [#729](https://github.com/collerek/ormar/issues/729) -## 🐛 Fixes +###🐛 Fixes * Fix limiting query result to 0 should return empty list (by @SepehrBazyar - thanks!) [#766](https://github.com/collerek/ormar/issues/713) -## 💬 Other +###💬 Other * Add dark mode to docs (by @SepehrBazyar - thanks!) [#717](https://github.com/collerek/ormar/pull/717) * Update aiomysql dependency [#778](https://github.com/collerek/ormar/issues/778) -# 0.11.2 +##0.11.2 -## 🐛 Fixes +###🐛 Fixes * Fix database drivers being required, while they should be optional [#713](https://github.com/collerek/ormar/issues/713) * Fix boolean field problem in `limit` queries in postgres without `limit_raw_sql` flag [#704](https://github.com/collerek/ormar/issues/704) * Fix enum_class spilling to schema causing errors in OpenAPI [#699](https://github.com/collerek/ormar/issues/699) -# 0.11.1 +##0.11.1 -## 🐛 Fixes +###🐛 Fixes * Fix deepcopy issues introduced in pydantic 1.9 [#685](https://github.com/collerek/ormar/issues/685) -# 0.11.0 +##0.11.0 -## ✨ Breaking Changes +###✨ Breaking Changes * Dropped support for python 3.6 * `Queryset.get_or_create` returns now a tuple with model and bool value indicating if the model was created (by @MojixCoder - thanks!) [#554](https://github.com/collerek/ormar/pull/554) * `Queryset.count()` now counts the number of distinct parent model rows by default, counting all rows is possible by setting `distinct=False` (by @erichaydel - thanks) [#588](https://github.com/collerek/ormar/pull/588) -## ✨ Features +###✨ Features * Added support for python 3.10 -## 🐛 Fixes +###🐛 Fixes * Fix inconsistent `JSON` fields behaviour in `save` and `bulk_create` [#584](https://github.com/collerek/ormar/issues/584) * Fix maximum recursion error [#580](https://github.com/collerek/ormar/pull/580) -# 0.10.25 +##0.10.25 -## ✨ Features +###✨ Features * Add `queryset_class` option to `Model.Meta` that allows you to easily swap `QuerySet` for your Model (by @ponytailer - thanks!) [#538](https://github.com/collerek/ormar/pull/538) * Allow passing extra `kwargs` to `IndexColumns` that will be passed to sqlalchemy `Index` (by @zevisert - thanks) [#575](https://github.com/collerek/ormar/pull/538) -## 🐛 Fixes +###🐛 Fixes * Fix nullable setting on `JSON` fields [#529](https://github.com/collerek/ormar/issues/529) * Fix bytes/str mismatch in bulk operations when using orjson instead of json (by @ponytailer - thanks!) [#538](https://github.com/collerek/ormar/pull/538) -# 0.10.24 +##0.10.24 -## ✨ Features +###✨ Features * Add `post_bulk_update` signal (by @ponytailer - thanks!) [#524](https://github.com/collerek/ormar/pull/524) -## 🐛 Fixes +###🐛 Fixes * Fix support for `pydantic==1.9.0` [#502](https://github.com/collerek/ormar/issues/502) * Fix timezone issues with datetime [#504](https://github.com/collerek/ormar/issues/504) * Remove literal binds in query generation to unblock postgres arrays [#/tophat/ormar-postgres-extensions/9](https://github.com/tophat/ormar-postgres-extensions/pull/9) * Fix bulk update for `JSON` fields [#519](https://github.com/collerek/ormar/issues/519) -## 💬 Other +###💬 Other * Improve performance of `bulk_create` by bypassing `databases` `execute_many` suboptimal implementation. (by @Mng-dev-ai thanks!) [#520](https://github.com/collerek/ormar/pull/520) * Bump min. required `databases` version to `>=5.4`. -# 0.10.23 +##0.10.23 -## ✨ Features +###✨ Features * Add ability to pass `comment` to sqlalchemy when creating a column [#485](https://github.com/collerek/ormar/issues/485) -## 🐛 Fixes +###🐛 Fixes * Fix `LargeBinary` fields that can be nullable [#409](https://github.com/collerek/ormar/issues/409) * Make `ormar.Model` pickable [#413](https://github.com/collerek/ormar/issues/413) * Make `first()` and `get()` without arguments respect ordering of main model set by user, fallback to primary key (asc, and desc respectively) [#453](https://github.com/collerek/ormar/issues/453) * Fix improper quoting of non-aliased join `on` clauses in postgress [#455](https://github.com/collerek/ormar/issues/455) -# 0.10.22 +##0.10.22 -## 🐛 Fixes +###🐛 Fixes * Hot fix for validators not being inherited when parent `ormar` model was set [#365](https://github.com/collerek/ormar/issues/365) -# 0.10.21 +##0.10.21 -## 🐛 Fixes +###🐛 Fixes * Add `ormar` implementation of `construct` classmethod that allows to build `Model` instances without validating the input to speed up the whole flow, if your data is already validated [#318](https://github.com/collerek/ormar/issues/318) * Fix for "inheriting" field validators from `ormar` model when newly created pydanic model is generated with `get_pydantic` [#365](https://github.com/collerek/ormar/issues/365) -# 0.10.20 +##0.10.20 -## ✨ Features +###✨ Features * Add `extra` parameter in `Model.Meta` that accepts `Extra.ignore` and `Extra.forbid` (default) and either ignores the extra fields passed to `ormar` model or raises an exception if one is encountered [#358](https://github.com/collerek/ormar/issues/358) -## 🐛 Fixes +###🐛 Fixes * Allow `None` if field is nullable and have choices set [#354](https://github.com/collerek/ormar/issues/354) * Always set `primary_key` to `not null` regardless of `autoincrement` and explicit `nullable` setting to avoid problems with migrations [#348](https://github.com/collerek/ormar/issues/348) -# 0.10.19 +##0.10.19 -## ✨ Features +###✨ Features * Add support for multi-column non-unique `IndexColumns` in `Meta.constraints` [#307](https://github.com/collerek/ormar/issues/307) * Add `sql_nullable` field attribute that allows to set different nullable setting for pydantic model and for underlying sql column [#308](https://github.com/collerek/ormar/issues/308) -## 🐛 Fixes +###🐛 Fixes * Enable caching of relation map to increase performance [#337](https://github.com/collerek/ormar/issues/337) * Clarify and fix documentation in regard of nullable fields [#339](https://github.com/collerek/ormar/issues/339) -## 💬 Other +###💬 Other * Bump supported `databases` version to `<=5.2`. -# 0.10.18 +##0.10.18 -## 🐛 Fixes +###🐛 Fixes * Fix order of fields in pydantic models [#328](https://github.com/collerek/ormar/issues/328) * Fix databases 0.5.0 support [#142](https://github.com/collerek/ormar/issues/142) -# 0.10.17 +##0.10.17 -## ✨ Features +###✨ Features * Allow overwriting the default pydantic type for model fields [#312](https://github.com/collerek/ormar/issues/312) * Add support for `sqlalchemy` >=1.4 (requires `databases` >= 0.5.0) [#142](https://github.com/collerek/ormar/issues/142) -# 0.10.16 +##0.10.16 -## ✨ Features +###✨ Features * Allow passing your own pydantic `Config` to `ormar.Model` that will be merged with the default one by @naturalethic (thanks!) [#285](https://github.com/collerek/ormar/issues/285) * Add `SmallInteger` field type by @ProgrammerPlus1998 (thanks!) [#297](https://github.com/collerek/ormar/pull/297) -## 🐛 Fixes +###🐛 Fixes * Fix generating openapi schema by removing obsolete pydantic field parameters that were directly exposed in schema [#291](https://github.com/collerek/ormar/issues/291) * Fix unnecessary warning for auto generated through models [#295](https://github.com/collerek/ormar/issues/295) -# 0.10.15 +##0.10.15 -## 🐛 Fixes +###🐛 Fixes * Fix generating pydantic models tree with nested models (by @pawamoy - thanks!) [#278](https://github.com/collerek/ormar/issues/278) * Fix missing f-string in warning about missing primary key field [#274](https://github.com/collerek/ormar/issues/274) * Fix passing foreign key value as relation (additional guard, fixed already in the latest release) [#270](https://github.com/collerek/ormar/issues/270) -# 0.10.14 +##0.10.14 -## ✨ Features +###✨ Features * Allow passing `timezone:bool = False` parameter to `DateTime` and `Time` fields for timezone aware database columns [#264](https://github.com/collerek/ormar/issues/264) * Allow passing datetime, date and time for filter on `DateTime`, `Time` and `Date` fields to allow filtering by datetimes instead of converting the value to string [#79](https://github.com/collerek/ormar/issues/79) -## 🐛 Fixes +###🐛 Fixes * Fix dependencies from `psycopg2` to `psycopg2-binary` [#255](https://github.com/collerek/ormar/issues/255) -# 0.10.13 +##0.10.13 -## ✨ Features +###✨ Features * Allow passing field accessors in `select_related` and `prefetch_related` aka. python style `select_related` [#225](https://github.com/collerek/ormar/issues/225). * Previously: @@ -232,21 +560,21 @@ Note that setting this flag will cause two queries for each upserted model -> `g await Author.objects.prefetch_related(Author.posts.categories).get() ``` -## 🐛 Fixes +###🐛 Fixes * Fix overwriting default value for inherited primary key [#253](https://github.com/collerek/ormar/issues/253) -# 0.10.12 +##0.10.12 -## 🐛 Fixes +###🐛 Fixes * Fix `QuerySet.create` method not using init (if custom provided) [#245](https://github.com/collerek/ormar/issues/245) * Fix `ForwardRef` `ManyToMany` relation setting wrong pydantic type [#250](https://github.com/collerek/ormar/issues/250) -# 0.10.11 +##0.10.11 -## ✨ Features +###✨ Features * Add `values` and `values_list` to `QuerySet` and `QuerysetProxy` that allows to return raw data from query [#223](https://github.com/collerek/ormar/issues/223). * Allow returning list of tuples or list of dictionaries from a query @@ -254,53 +582,53 @@ Note that setting this flag will cause two queries for each upserted model -> `g * Allow excluding models in between in chain of relations, so you can extract only needed columns * `values_list` allows you to flatten the result if you extract only one column. -## 🐛 Fixes +###🐛 Fixes * Fix creation of auto through model for m2m relation with ForwardRef [#226](https://github.com/collerek/ormar/issues/226) -# 0.10.10 +##0.10.10 -## ✨ Features +###✨ Features * Add [`get_pydantic`](https://collerek.github.io/ormar/models/methods/#get_pydantic) flag that allows you to auto generate equivalent pydantic models tree from ormar.Model. This newly generated model tree can be used in requests and responses to exclude fields you do not want to include in the data. * Add [`exclude_parent_fields`](https://collerek.github.io/ormar/models/inheritance/#exclude_parent_fields) parameter to model Meta that allows you to exclude fields from parent models during inheritance. Note that best practice is to combine models and mixins but if you have many similar models and just one that differs it might be useful tool to achieve that. -## 🐛 Fixes +###🐛 Fixes * Fix is null filter with pagination and relations (by @erichaydel) [#214](https://github.com/collerek/ormar/issues/214) * Fix not saving child object on reverse side of the relation if not saved before [#216](https://github.com/collerek/ormar/issues/216) -## 💬 Other +###💬 Other * Expand [fastapi](https://collerek.github.io/ormar/fastapi) part of the documentation to show samples of using ormar in requests and responses in fastapi. * Improve the docs in regard of `default`, `ForeignKey.add` etc. -# 0.10.9 +##0.10.9 -## Important security fix +###Important security fix * Update pin for pydantic to fix security vulnerability [CVE-2021-29510](https://github.com/samuelcolvin/pydantic/security/advisories/GHSA-5jqp-qgf6-3pvh) You are advised to update to version of pydantic that was patched. In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. -## 🐛 Fixes +###🐛 Fixes * Fix OpenAPi schema for LargeBinary [#204](https://github.com/collerek/ormar/issues/204) -# 0.10.8 +##0.10.8 -## 🐛 Fixes +###🐛 Fixes * Fix populating default values in pk_only child models [#202](https://github.com/collerek/ormar/issues/202) * Fix mypy for LargeBinary fields with base64 str representation [#199](https://github.com/collerek/ormar/issues/199) * Fix OpenAPI schema format for LargeBinary fields with base64 str representation [#199](https://github.com/collerek/ormar/issues/199) * Fix OpenAPI choices encoding for LargeBinary fields with base64 str representation -# 0.10.7 +##0.10.7 -## ✨ Features +###✨ Features * Add `exclude_primary_keys: bool = False` flag to `dict()` method that allows to exclude all primary key columns in the resulting dictionaru. [#164](https://github.com/collerek/ormar/issues/164) * Add `exclude_through_models: bool = False` flag to `dict()` that allows excluding all through models from `ManyToMany` relations [#164](https://github.com/collerek/ormar/issues/164) @@ -308,19 +636,19 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. on access to attribute and string is converted to bytes on setting. Data in database is stored as bytes. [#187](https://github.com/collerek/ormar/issues/187) * Add `pk` alias to allow field access by `Model.pk` in filters and order by clauses (python style) -## 🐛 Fixes +###🐛 Fixes * Remove default `None` option for `max_length` for `LargeBinary` field [#186](https://github.com/collerek/ormar/issues/186) * Remove default `None` option for `max_length` for `String` field -## 💬 Other +###💬 Other * Provide a guide and samples of `dict()` parameters in the [docs](https://collerek.github.io/ormar/models/methods/) * Major refactor of getting/setting attributes from magic methods into descriptors -> noticeable performance improvement -# 0.10.6 +##0.10.6 -## ✨ Features +###✨ Features * Add `LargeBinary(max_length)` field type [#166](https://github.com/collerek/ormar/issues/166) * Add support for normal pydantic fields (including Models) instead of `pydantic_only` @@ -340,30 +668,30 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. The same algorithm is used to iterate related models without looks as with `dict()` and `select/load_all`. Examples appear also in `fastapi`. [#157](https://github.com/collerek/ormar/issues/157) -## 🐛 Fixes +###🐛 Fixes * By default `pydantic` is not validating fields during assignment, which is not a desirable setting for an ORM, now all `ormar.Models` have validation turned-on during assignment (like `model.column = 'value'`) -## 💬 Other +###💬 Other * Add connecting to the database in QuickStart in readme [#180](https://github.com/collerek/ormar/issues/180) * OpenAPI schema does no longer include `ormar.Model` docstring as description, instead just model name is provided if you do not provide your own docstring. * Some performance improvements. -# 0.10.5 +##0.10.5 -## 🐛 Fixes +###🐛 Fixes * Fix bug in `fastapi-pagination` [#73](https://github.com/uriyyo/fastapi-pagination/issues/73) * Remove unnecessary `Optional` in `List[Optional[T]]` in return value for `QuerySet.all()` and `Querysetproxy.all()` return values [#174](https://github.com/collerek/ormar/issues/174) * Run tests coverage publish only on internal prs instead of all in github action. -# 0.10.4 +##0.10.4 -## ✨ Features +###✨ Features * Add **Python style** to `filter` and `order_by` with field access instead of dunder separated strings. [#51](https://github.com/collerek/ormar/issues/51) * Accessing a field with attribute access (chain of dot notation) can be used to construct `FilterGroups` (`ormar.and_` and `ormar.or_`) @@ -475,15 +803,15 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. * You can of course also combine different models and many order_bys: `Product.objects.order_by([Product.category.name.asc(), Product.name.desc()]).all()` -## 🐛 Fixes +### 🐛 Fixes * Not really a bug but rather inconsistency. Providing a filter with nested model i.e. `album__category__name = 'AA'` is checking if album and category models are included in `select_related()` and if not it's auto-adding them there. The same functionality was not working for `FilterGroups` (`and_` and `or_`), now it works (also for python style filters which return `FilterGroups`). -# 0.10.3 +## 0.10.3 -## ✨ Features +### ✨ Features * `ForeignKey` and `ManyToMany` now support `skip_reverse: bool = False` flag [#118](https://github.com/collerek/ormar/issues/118). If you set `skip_reverse` flag internally the field is still registered on the other @@ -511,7 +839,7 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. * By default `Through` model relation names default to related model name in lowercase. So in example like this: ```python - ... # course declaration omitted + ... ## course declaration omitted class Student(ormar.Model): class Meta: database = database @@ -521,7 +849,7 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. name: str = ormar.String(max_length=100) courses = ormar.ManyToMany(Course) - # will produce default Through model like follows (example simplified) + ## will produce default Through model like follows (example simplified) class StudentCourse(ormar.Model): class Meta: database = database @@ -529,7 +857,7 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. tablename = "students_courses" id: int = ormar.Integer(primary_key=True) - student = ormar.ForeignKey(Student) # default name + student = ormar.ForeignKey(Student) ## default name course = ormar.ForeignKey(Course) # default name ``` * To customize the names of fields/relation in Through model now you can use new parameters to `ManyToMany`: @@ -562,22 +890,22 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. course_id = ormar.ForeignKey(Course) # set by through_reverse_relation_name ``` -## 🐛 Fixes +### 🐛 Fixes * Fix weakref `ReferenceError` error [#118](https://github.com/collerek/ormar/issues/118) * Fix error raised by Through fields when pydantic `Config.extra="forbid"` is set * Fix bug with `pydantic.PrivateAttr` not being initialized at `__init__` [#149](https://github.com/collerek/ormar/issues/149) * Fix bug with pydantic-type `exclude` in `dict()` with `__all__` key not working -## 💬 Other +### 💬 Other * Introduce link to `sqlalchemy-to-ormar` auto-translator for models * Provide links to fastapi ecosystem libraries that support `ormar` * Add transactions to docs (supported with `databases`) -# 0.10.2 +## 0.10.2 -## ✨ Features +### ✨ Features * `Model.save_related(follow=False)` now accept also two additional arguments: `Model.save_related(follow=False, save_all=False, exclude=None)`. * `save_all:bool` -> By default (so with `save_all=False`) `ormar` only upserts models that are not saved (so new or updated ones), @@ -598,7 +926,7 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. * Same thing applies to `QuerysetProxy.update(each=False, **kwargs)` which also previously required that you either pass a `filter` (by `**kwargs` or as a separate `filter()` call) or set `each=True` now also accepts `exclude()` calls that generates NOT filter. So either `each=True` needs to be set to update whole table or at least one of `filter/exclude` clauses. -## 🐛 Fixes +### 🐛 Fixes * Fix improper relation field resolution in `QuerysetProxy` if fk column has different database alias. * Fix hitting recursion error with very complicated models structure with loops when calling `dict()`. @@ -607,32 +935,32 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. * Fix bug when bulk_create would try to save also `property_field` decorated methods and `pydantic` fields * Fix wrong merging of deeply nested chain of reversed relations -## 💬 Other +### 💬 Other * Performance optimizations * Split tests into packages based on tested area -# 0.10.1 +## 0.10.1 -## Features +### Features * add `get_or_none(**kwargs)` method to `QuerySet` and `QuerysetProxy`. It is exact equivalent of `get(**kwargs)` but instead of raising `ormar.NoMatch` exception if there is no db record matching the criteria, `get_or_none` simply returns `None`. -## Fixes +### Fixes * Fix dialect dependent quoting of column and table names in order_by clauses not working properly in postgres. -# 0.10.0 +## 0.10.0 -## Breaking +### Breaking * Dropped supported for long deprecated notation of field definition in which you use ormar fields as type hints i.e. `test_field: ormar.Integger() = None` * Improved type hints -> `mypy` can properly resolve related models fields (`ForeignKey` and `ManyToMany`) as well as return types of `QuerySet` methods. Those mentioned are now returning proper model (i.e. `Book`) instead or `ormar.Model` type. There is still problem with reverse sides of relation and `QuerysetProxy` methods, to ease type hints now those return `Any`. Partially fixes #112. -## Features +### Features * add `select_all(follow: bool = False)` method to `QuerySet` and `QuerysetProxy`. It is kind of equivalent of the Model's `load_all()` method but can be used directly in a query. @@ -641,14 +969,14 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. so you still have to issue `get()`, `all()` etc. as `select_all()` returns a QuerySet (or proxy) like `fields()` or `order_by()`. -## Internals +### Internals * `ormar` fields are no longer stored as classes in `Meta.model_fields` dictionary but instead they are stored as instances. -# 0.9.9 +## 0.9.9 -## Features +### Features * Add possibility to change default ordering of relations and models. * To change model sorting pass `orders_by = [columns]` where `columns: List[str]` to model `Meta` class * To change relation order_by pass `orders_by = [columns]` where `columns: List[str]` @@ -677,7 +1005,7 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. `relation_name: str` - name of the relation to which child is added, for add signals also `passed_kwargs: Dict` - dict of kwargs passed to `add()` -## Changes +### Changes * `Through` models for ManyToMany relations are now instantiated on creation, deletion and update, so you can provide not only autoincrement int as a primary key but any column type with default function provided. * Since `Through` models are now instantiated you can also subscribe to `Through` model @@ -685,15 +1013,15 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. * `pre_update` signals receivers now get also passed_args argument which is a dict of values passed to update function if any (else empty dict) -## Fixes +### Fixes * `pre_update` signal now is sent before the extraction of values so you can modify the passed instance in place and modified fields values will be reflected in database * `bulk_update` now works correctly also with `UUID` primary key column type -# 0.9.8 +## 0.9.8 -## Features +### Features * Add possibility to encrypt the selected field(s) in the database * As minimum you need to provide `encrypt_secret` and `encrypt_backend` * `encrypt_backend` can be one of the `ormar.EncryptBackends` enum (`NONE, FERNET, HASH, CUSTOM`) - default: `NONE` @@ -706,12 +1034,12 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. * Note that in HASH backend you can filter by full value but filters like `contain` will not work as comparison is make on encrypted values * Note that adding `encrypt_backend` changes the database column type to `TEXT`, which needs to be reflected in db either by migration or manual change -## Fixes +### Fixes * (Advanced/ Internal) Restore custom sqlalchemy types (by `types.TypeDecorator` subclass) functionality that ceased to working so `process_result_value` was never called -# 0.9.7 +## 0.9.7 -## Features +### Features * Add `isnull` operator to filter and exclude methods. ```python album__name__isnull=True #(sql: album.name is null) @@ -734,10 +1062,10 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. ``` Check the updated docs in Queries -> Filtering and sorting -> Complex filters -## Other +### Other * Setting default on `ForeignKey` or `ManyToMany` raises and `ModelDefinition` exception as it is (and was) not supported -# 0.9.6 +## 0.9.6 ##Important * `Through` model for `ManyToMany` relations now **becomes optional**. It's not a breaking change @@ -749,7 +1077,7 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. Note that you still need to provide it if you want to customize the `Through` model name or the database table name. -## Features +### Features * Add `update` method to `QuerysetProxy` so now it's possible to update related models directly from parent model in `ManyToMany` relations and in reverse `ForeignKey` relations. Note that update like in `QuerySet` `update` returns number of updated models and **does not update related models in place** on parent model. To get the refreshed data on parent model you need to refresh @@ -772,27 +1100,27 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. but now if you try to do so `ModelDefinitionError` will be thrown * check the updated ManyToMany relation docs for more information -# Other +## Other * Updated docs and api docs * Refactors and optimisations mainly related to filters, exclusions and order bys -# 0.9.5 +## 0.9.5 -## Fixes +### Fixes * Fix creation of `pydantic` FieldInfo after update of `pydantic` to version >=1.8 * Pin required dependency versions to avoid such situations in the future -# 0.9.4 +## 0.9.4 -## Fixes +### Fixes * Fix `fastapi` OpenAPI schema generation for automatic docs when multiple models refer to the same related one -# 0.9.3 +## 0.9.3 -## Fixes +### Fixes * Fix `JSON` field being double escaped when setting value after initialization * Fix `JSON` field not respecting `nullable` field setting due to `pydantic` internals * Fix `choices` verification for `JSON` field @@ -800,25 +1128,25 @@ In 0.10.9 ormar excludes versions with vulnerability in pinned dependencies. * Fix `choices` not being verified during `update` call from `QuerySet` -# 0.9.2 +## 0.9.2 -## Other +### Other * Updated the Quick Start in docs/readme * Updated docs with links to queries subpage * Added badges for code climate and pepy downloads -# 0.9.1 +## 0.9.1 -## Features +### Features * Add choices values to `OpenAPI` specs, so it looks like native `Enum` field in the result schema. -## Fixes +### Fixes * Fix `choices` behavior with `fastapi` usage when special fields can be not initialized yet but passed as strings etc. -# 0.9.0 +## 0.9.0 -## Important +### Important * **Braking Fix:** Version 0.8.0 introduced a bug that prevents generation of foreign_keys constraint in the database, both in alembic and during creation through sqlalchemy.engine, this is fixed now. * **THEREFORE IF YOU USE VERSION >=0.8.0 YOU ARE STRONGLY ADVISED TO UPDATE** cause despite @@ -828,7 +1156,7 @@ that most of the `ormar` functions are working your database **CREATED with orma should be fine nevertheless you should update to reflect all future schema updates in your models. -## Breaking +### Breaking * **Breaking:** All foreign_keys and unique constraints now have a name so `alembic` can identify them in db and not depend on db * **Breaking:** During model construction if `Meta` class of the `Model` does not @@ -839,14 +1167,14 @@ for sqlite backend, meaning that each query is run with a new connection and the This is changed in `ormar` since >=0.9.0 and by default each sqlite3 query has `"PRAGMA foreign_keys=1;"` run so now each sqlite3 connection by default enforces ForeignKey constraints including cascades. -## Other +### Other * Update api docs. * Add tests for fk creation in db and for cascades in db -# 0.8.1 +## 0.8.1 -## Features +### Features * Introduce processing of `ForwardRef` in relations. Now you can create self-referencing models - both `ForeignKey` and `ManyToMany` relations. @@ -864,15 +1192,15 @@ for sqlite backend, meaning that each query is run with a new connection and the * Introduce the `paginate` method that allows to limit/offset by `page` and `page_size`. Available for `QuerySet` and `QuerysetProxy`. -## Other +### Other * Refactoring and performance optimization in queries and joins. * Add python 3.9 to tests and pypi setup. * Update API docs and docs -> i.e. split of queries documentation. -# 0.8.0 +## 0.8.0 -## Breaking +### Breaking * **Breaking:** `remove()` parent from child side in reverse ForeignKey relation now requires passing a relation `name`, as the same model can be registered multiple times and `ormar` needs to know from which relation on the parent you want to remove the child. * **Breaking:** applying `limit` and `offset` with `select_related` is by default applied only on the main table before the join -> meaning that not the total @@ -881,20 +1209,20 @@ as the same model can be registered multiple times and `ormar` needs to know fro * **Breaking:** issuing `get()` **without any filters** now fetches the first row ordered by the primary key desc (so should be last one inserted (can be different for non number primary keys - i.e. alphabetical order of string)) * **Breaking (internal):** sqlalchemy columns kept at `Meta.columns` are no longer bind to table, so you cannot get the column straight from there -## Features +### Features * Introduce **inheritance**. For now two types of inheritance are possible: * **Mixins** - don't subclass `ormar.Model`, just define fields that are later used on different models (like `created_date` and `updated_date` on each child model), only actual models create tables, but those fields from mixins are added * **Concrete table inheritance** - means that parent is marked as `abstract=True` in Meta class and each child has its own table with columns from the parent and own child columns, kind of similar to Mixins but parent also is a (an abstract) Model * To read more check the docs on models -> inheritance section. * QuerySet `first()` can be used with `prefetch_related` -## Fixes +### Fixes * Fix minor bug in `order_by` for primary model order bys * Fix in `prefetch_query` for multiple related_names for the same model. * Fix using same `related_name` on different models leading to the same related `Model` overwriting each other, now `ModelDefinitionError` is raised and you need to change the name. * Fix `order_by` overwriting conditions when multiple joins to the same table applied. -## Docs +### Docs * Split and cleanup in docs: * Divide models section into subsections * Divide relations section into subsections @@ -902,11 +1230,11 @@ as the same model can be registered multiple times and `ormar` needs to know fro * Add model inheritance section * Add API (BETA) documentation -# 0.7.5 +## 0.7.5 * Fix for wrong relation column name in many_to_many relation joins (fix [#73][#73]) -# 0.7.4 +## 0.7.4 * Allow multiple relations to the same related model/table. * Fix for wrong relation column used in many_to_many relation joins (fix [#73][#73]) @@ -914,19 +1242,19 @@ as the same model can be registered multiple times and `ormar` needs to know fro * Add check if user provide related_name if there are multiple relations to same table on one model. * More eager cleaning of the dead weak proxy models. -# 0.7.3 +## 0.7.3 * Fix for setting fetching related model with UUDI pk, which is a string in raw (fix [#71][#71]) -# 0.7.2 +## 0.7.2 * Fix for overwriting related models with pk only in `Model.update() with fields passed as parameters` (fix [#70][#70]) -# 0.7.1 +## 0.7.1 * Fix for overwriting related models with pk only in `Model.save()` (fix [#68][#68]) -# 0.7.0 +## 0.7.0 * **Breaking:** QuerySet `bulk_update` method now raises `ModelPersistenceError` for unsaved models passed instead of `QueryDefinitionError` * **Breaking:** Model initialization with unknown field name now raises `ModelError` instead of `KeyError` @@ -936,7 +1264,7 @@ as the same model can be registered multiple times and `ormar` needs to know fro * Performance optimization * Updated docs -# 0.6.2 +## 0.6.2 * Performance optimization * Fix for bug with `pydantic_only` fields being required @@ -944,11 +1272,11 @@ as the same model can be registered multiple times and `ormar` needs to know fro be included in `Model.model_dump()` and in `fastapi` response * Update docs -# 0.6.1 +## 0.6.1 * Explicitly set None to excluded nullable fields to avoid pydantic setting a default value (fix [#60][#60]). -# 0.6.0 +## 0.6.0 * **Breaking:** calling instance.load() when the instance row was deleted from db now raises `NoMatch` instead of `ValueError` * **Breaking:** calling add and remove on ReverseForeignKey relation now updates the child model in db setting/removing fk column @@ -960,12 +1288,12 @@ as the same model can be registered multiple times and `ormar` needs to know fro so now you can use those methods directly from relation * Update docs -# 0.5.5 +## 0.5.5 * Fix for alembic autogenaration of migration `UUID` columns. It should just produce sqlalchemy `CHAR(32)` or `CHAR(36)` * In order for this to work you have to set user_module_prefix='sa.' (must be equal to sqlalchemy_module_prefix option (default 'sa.')) -# 0.5.4 +## 0.5.4 * Allow to pass `uuid_format` (allowed 'hex'(default) or 'string') to `UUID` field to change the format in which it's saved. By default field is saved in hex format (trimmed to 32 chars (without dashes)), but you can pass @@ -975,21 +1303,21 @@ so now you can use those methods directly from relation * hex value = c616ab438cce49dbbf4380d109251dce * string value = c616ab43-8cce-49db-bf43-80d109251dce -# 0.5.3 +## 0.5.3 * Fixed bug in `Model.model_dump()` method that was ignoring exclude parameter and not include dictionary argument. -# 0.5.2 +## 0.5.2 * Added `prefetch_related` method to load subsequent models in separate queries. * Update docs -# 0.5.1 +## 0.5.1 * Switched to github actions instead of travis * Update badges in the docs -# 0.5.0 +## 0.5.0 * Added save status -> you can check if model is saved with `ModelInstance.saved` property * Model is saved after `save/update/load/upsert` method on model @@ -1010,7 +1338,7 @@ so now you can use those methods directly from relation * Optional performance dependency orjson added (**strongly recommended**) * Updated docs -# 0.4.4 +## 0.4.4 * add exclude_fields() method to exclude fields from sql * refactor column names setting (aliases) @@ -1018,20 +1346,20 @@ so now you can use those methods directly from relation * additional tests for fields and exclude_fields * update docs -# 0.4.3 +## 0.4.3 * include properties in models.model_dump() and model.model_dump_json() -# 0.4.2 +## 0.4.2 * modify creation of pydantic models to allow returning related models with only pk populated -# 0.4.1 +## 0.4.1 * add order_by method to queryset to allow sorting * update docs -# 0.4.0 +## 0.4.0 * Changed notation in Model definition -> now use name = ormar.Field() not name: ormar.Field() * Note that old notation is still supported but deprecated and will not play nice with static checkers like mypy and pydantic pycharm plugin @@ -1043,42 +1371,42 @@ so now you can use those methods directly from relation * Add mypy and pydantic plugin to docs * Expand the docs on ManyToMany relation -# 0.3.11 +## 0.3.11 * Fix setting server_default as default field value in python -# 0.3.10 +## 0.3.10 * Fix postgresql check to avoid exceptions with drivers not installed if using different backend -# 0.3.9 +## 0.3.9 * Fix json schema generation as of [#19][#19] * Fix for not initialized ManyToMany relations in fastapi copies of ormar.Models * Update docs in regard of fastapi use * Add tests to verify fastapi/docs proper generation -# 0.3.8 +## 0.3.8 * Added possibility to provide alternative database column names with name parameter to all fields. * Fix bug with selecting related ManyToMany fields with `fields()` if they are empty. * Updated documentation -# 0.3.7 +## 0.3.7 * Publish documentation and update readme -# 0.3.6 +## 0.3.6 * Add fields() method to limit the selected columns from database - only nullable columns can be excluded. * Added UniqueColumns and constraints list in model Meta to build unique constraints on list of columns. * Added UUID field type based on Char(32) column type. -# 0.3.5 +## 0.3.5 * Added bulk_create and bulk_update for operations on multiple objects. -# 0.3.4 +## 0.3.4 Add queryset level methods * delete @@ -1086,21 +1414,21 @@ Add queryset level methods * get_or_create * update_or_create -# 0.3.3 +## 0.3.3 * Add additional filters - startswith and endswith -# 0.3.2 +## 0.3.2 * Add choices parameter to all fields - limiting the accepted values to ones provided -# 0.3.1 +## 0.3.1 * Added exclude to filter where not conditions. * Added tests for mysql and postgres with fixes for postgres. * Rafactors and cleanup. -# 0.3.0 +## 0.3.0 * Added ManyToMany field and support for many to many relations diff --git a/docs/signals.md b/docs/signals.md index cdd7b7601..81ad965e9 100644 --- a/docs/signals.md +++ b/docs/signals.md @@ -54,7 +54,7 @@ for which you want to run the signal receiver. Currently there is no way to set signal for all models at once without explicitly passing them all into registration of receiver. -```Python hl_lines="27-30" +```Python hl_lines="28-31" --8<-- "../docs_src/signals/docs002.py" ``` @@ -65,7 +65,7 @@ Currently there is no way to set signal for all models at once without explicitl Note that our newly created function has instance and class of the instance so you can easily run database queries inside your receivers if you want to. -```Python hl_lines="40-47" +```Python hl_lines="41-48" --8<-- "../docs_src/signals/docs002.py" ``` @@ -78,7 +78,7 @@ async def before_update(sender, instance, **kwargs): print(f"{sender.get_name()}: {instance.model_dump_json()}: {kwargs}") ``` -Of course you can also create multiple functions for the same signal and model. Each of them will run at each signal. +Of course, you can also create multiple functions for the same signal and model. Each of them will run at each signal. ```python @pre_update(Album) @@ -142,7 +142,7 @@ album.signals.pre_save.disconnect(before_save) * bulk operations (`QuerySet.bulk_create` and `QuerySet.bulk_update`) as they are designed for speed. * queryset table level operations (`QuerySet.update` and `QuerySet.delete`) as they run on the underlying tables - (more lak raw sql update/delete operations) and do not have specific instance. + (more like raw sql update/delete operations) and do not have specific instance. ### pre_save diff --git a/docs_src/queries/docs001.py b/docs_src/queries/docs001.py index 94dde1bde..dd38ac84c 100644 --- a/docs_src/queries/docs001.py +++ b/docs_src/queries/docs001.py @@ -7,7 +7,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/queries/docs002.py b/docs_src/queries/docs002.py index 1c3306819..d30e13d55 100644 --- a/docs_src/queries/docs002.py +++ b/docs_src/queries/docs002.py @@ -8,7 +8,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/queries/docs003.py b/docs_src/queries/docs003.py index 09b928e75..1c1e0aec8 100644 --- a/docs_src/queries/docs003.py +++ b/docs_src/queries/docs003.py @@ -8,7 +8,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/queries/docs004.py b/docs_src/queries/docs004.py index f23760046..46974099b 100644 --- a/docs_src/queries/docs004.py +++ b/docs_src/queries/docs004.py @@ -8,7 +8,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/queries/docs005.py b/docs_src/queries/docs005.py index ff9a3606f..5f3accacf 100644 --- a/docs_src/queries/docs005.py +++ b/docs_src/queries/docs005.py @@ -8,7 +8,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/queries/docs006.py b/docs_src/queries/docs006.py index 0367f6c74..f5b9d52e1 100644 --- a/docs_src/queries/docs006.py +++ b/docs_src/queries/docs006.py @@ -8,7 +8,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/queries/docs007.py b/docs_src/queries/docs007.py index 6b5189236..b1a09fc70 100644 --- a/docs_src/queries/docs007.py +++ b/docs_src/queries/docs007.py @@ -8,7 +8,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/queries/docs008.py b/docs_src/queries/docs008.py index f60ab6772..814a0b989 100644 --- a/docs_src/queries/docs008.py +++ b/docs_src/queries/docs008.py @@ -9,7 +9,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/queries/docs009.py b/docs_src/queries/docs009.py index 3a336fc05..93ce404c5 100644 --- a/docs_src/queries/docs009.py +++ b/docs_src/queries/docs009.py @@ -8,7 +8,8 @@ DATABASE_URL = "sqlite:///test.db" ormar_base_config = ormar.OrmarConfig( - database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData() + database=databases.Database(DATABASE_URL), + metadata=sqlalchemy.MetaData(), ) diff --git a/docs_src/select_columns/__init__.py b/docs_src/select_columns/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/select_columns/docs001.py b/docs_src/select_columns/docs001.py new file mode 100644 index 000000000..331e74767 --- /dev/null +++ b/docs_src/select_columns/docs001.py @@ -0,0 +1,63 @@ +import asyncio + +import databases +import ormar +import sqlalchemy +from tests.settings import DATABASE_URL + +base_ormar_config = ormar.OrmarConfig( + database=databases.Database(DATABASE_URL, force_rollback=True), + metadata=sqlalchemy.MetaData(), +) + + +class Company(ormar.Model): + ormar_config = base_ormar_config.copy(tablename="companies") + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + founded: int = ormar.Integer(nullable=True) + + +class Car(ormar.Model): + ormar_config = base_ormar_config.copy() + + id: int = ormar.Integer(primary_key=True) + manufacturer = ormar.ForeignKey(Company) + name: str = ormar.String(max_length=100) + year: int = ormar.Integer(nullable=True) + gearbox_type: str = ormar.String(max_length=20, nullable=True) + gears: int = ormar.Integer(nullable=True) + aircon_type: str = ormar.String(max_length=20, nullable=True) + + +async def sample_data(): + # build some sample data + toyota = await Company.objects.create(name="Toyota", founded=1937) + await Car.objects.create( + manufacturer=toyota, + name="Corolla", + year=2020, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", + ) + await Car.objects.create( + manufacturer=toyota, + name="Yaris", + year=2019, + gearbox_type="Manual", + gears=5, + aircon_type="Manual", + ) + await Car.objects.create( + manufacturer=toyota, + name="Supreme", + year=2020, + gearbox_type="Auto", + gears=6, + aircon_type="Auto", + ) + + +asyncio.run(sample_data()) From 5700bd67a28c57fff17c0d436f362298ed7cce0d Mon Sep 17 00:00:00 2001 From: collerek Date: Sat, 16 Mar 2024 20:25:01 +0100 Subject: [PATCH 93/95] create tables in new docs src --- docs_src/select_columns/docs001.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs_src/select_columns/docs001.py b/docs_src/select_columns/docs001.py index 331e74767..be760a62a 100644 --- a/docs_src/select_columns/docs001.py +++ b/docs_src/select_columns/docs001.py @@ -3,6 +3,7 @@ import databases import ormar import sqlalchemy +from examples import create_drop_database from tests.settings import DATABASE_URL base_ormar_config = ormar.OrmarConfig( @@ -31,6 +32,7 @@ class Car(ormar.Model): aircon_type: str = ormar.String(max_length=20, nullable=True) +@create_drop_database(base_config=base_ormar_config) async def sample_data(): # build some sample data toyota = await Company.objects.create(name="Toyota", founded=1937) From 6cb0af241472470e55b77aa6240d3bf2084d8878 Mon Sep 17 00:00:00 2001 From: collerek Date: Sat, 23 Mar 2024 19:14:45 +0100 Subject: [PATCH 94/95] cleanup old deps, uncomment docs publish on tag --- .github/workflows/deploy-docs.yml | 6 +- ormar/__init__.py | 8 +- poetry.lock | 376 +++++++++++++++--------------- pyproject.toml | 7 - 4 files changed, 188 insertions(+), 209 deletions(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 9014b9f61..70c3b9bf9 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -27,6 +27,6 @@ jobs: run: | echo $RELEASE_VERSION echo ${{ env.RELEASE_VERSION }} -# - name: Deploy -# run: | -# mike deploy --push --update-aliases ${{ env.RELEASE_VERSION }} latest + - name: Deploy + run: | + mike deploy --push --update-aliases ${{ env.RELEASE_VERSION }} latest diff --git a/ormar/__init__.py b/ormar/__init__.py index ae129b7ca..ab399719a 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -20,11 +20,8 @@ """ -try: - from importlib.metadata import version # type: ignore -except ImportError: # pragma: no cover - from importlib_metadata import version # type: ignore -from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I001 +from importlib.metadata import version + from ormar.decorators import ( # noqa: I100 post_bulk_update, post_delete, @@ -76,6 +73,7 @@ # noqa: I100 from ormar.models import ExcludableItems, Extra, Model, OrmarConfig +from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I001 from ormar.queryset import OrderAction, QuerySet, and_, or_ from ormar.relations import RelationType from ormar.signals import Signal diff --git a/poetry.lock b/poetry.lock index 657c01f6d..7752038be 100644 --- a/poetry.lock +++ b/poetry.lock @@ -209,34 +209,34 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "black" -version = "24.2.0" +version = "24.3.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "black-24.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29"}, - {file = "black-24.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430"}, - {file = "black-24.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f"}, - {file = "black-24.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a"}, - {file = "black-24.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd"}, - {file = "black-24.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2"}, - {file = "black-24.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92"}, - {file = "black-24.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23"}, - {file = "black-24.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b"}, - {file = "black-24.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9"}, - {file = "black-24.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693"}, - {file = "black-24.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982"}, - {file = "black-24.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4"}, - {file = "black-24.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218"}, - {file = "black-24.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0"}, - {file = "black-24.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d"}, - {file = "black-24.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8"}, - {file = "black-24.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8"}, - {file = "black-24.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540"}, - {file = "black-24.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31"}, - {file = "black-24.2.0-py3-none-any.whl", hash = "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6"}, - {file = "black-24.2.0.tar.gz", hash = "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894"}, + {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, + {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, + {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, + {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, + {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, + {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, + {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, + {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, + {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, + {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, + {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, + {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, + {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, + {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, + {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, + {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, + {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, + {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, + {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, + {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, + {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, + {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, ] [package.dependencies] @@ -268,76 +268,64 @@ files = [ [[package]] name = "cffi" -version = "1.15.1" +version = "1.16.0" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] [package.dependencies] @@ -500,64 +488,64 @@ files = [ [[package]] name = "coverage" -version = "7.4.3" +version = "7.4.4" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, - {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, - {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, - {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, - {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, - {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, - {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, - {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, - {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, - {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, - {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, - {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, - {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, - {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, + {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, + {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, + {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, + {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, + {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, + {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, + {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, + {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, + {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, + {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, + {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, + {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, ] [package.dependencies] @@ -698,20 +686,20 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "filelock" -version = "3.12.4" +version = "3.13.1" description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, - {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] -typing = ["typing-extensions (>=4.7.1)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "ghp-import" @@ -805,14 +793,14 @@ test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.41.3" +version = "0.42.1" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "griffe-0.41.3-py3-none-any.whl", hash = "sha256:27b4610f1ba6e5d039e9f0a2c97232e13463df75e53cb1833e0679f3377b9de2"}, - {file = "griffe-0.41.3.tar.gz", hash = "sha256:9edcfa9f57f4d9c5fcc6d5ce067c67a685b7101a21a7d11848ce0437368e474c"}, + {file = "griffe-0.42.1-py3-none-any.whl", hash = "sha256:7e805e35617601355edcac0d3511cedc1ed0cb1f7645e2d336ae4b05bbae7b3b"}, + {file = "griffe-0.42.1.tar.gz", hash = "sha256:57046131384043ed078692b85d86b76568a686266cc036b9b56b704466f803ce"}, ] [package.dependencies] @@ -906,14 +894,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.2" +version = "7.1.0" description = "Read metadata from Python packages" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100"}, - {file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792"}, + {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, ] [package.dependencies] @@ -922,18 +910,18 @@ zipp = ">=0.5" [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "importlib-resources" -version = "6.1.3" +version = "6.4.0" description = "Read resources from Python packages" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.3-py3-none-any.whl", hash = "sha256:4c0269e3580fe2634d364b39b38b961540a7738c02cb984e98add8b4221d793d"}, - {file = "importlib_resources-6.1.3.tar.gz", hash = "sha256:56fb4525197b78544a3354ea27793952ab93f935bb4bf746b846bb1015020f2b"}, + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, ] [package.dependencies] @@ -941,7 +929,7 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["jaraco.collections", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -975,14 +963,14 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "markdown" -version = "3.5.2" +version = "3.6" description = "Python implementation of John Gruber's Markdown." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, - {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, + {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"}, + {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"}, ] [package.dependencies] @@ -1919,25 +1907,25 @@ histogram = ["pygal", "pygaljs"] [[package]] name = "pytest-codspeed" -version = "2.2.0" +version = "2.2.1" description = "Pytest plugin to create CodSpeed benchmarks" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest_codspeed-2.2.0-py3-none-any.whl", hash = "sha256:5da48b842fc465926d122dd15bb86e86af5d9f0c53ec1b7c736e9a9aed558c13"}, - {file = "pytest_codspeed-2.2.0.tar.gz", hash = "sha256:665003fc20117b64a98d16ffd1008f5bd6bf3b1e9af142b98c00abff7f626bbd"}, + {file = "pytest_codspeed-2.2.1-py3-none-any.whl", hash = "sha256:aad08033015f3e6c8c14c8bf0eca475921a9b088e92c98b626bf8af8f516471e"}, + {file = "pytest_codspeed-2.2.1.tar.gz", hash = "sha256:0adc24baf01c64a6ca0a0b83b3cd704351708997e09ec086b7776c32227d4e0a"}, ] [package.dependencies] -cffi = ">=1.15.1,<1.16.0" -filelock = ">=3.12.2,<3.13.0" +cffi = ">=1.15.1" +filelock = ">=3.12.2" pytest = ">=3.8" -setuptools = {version = ">=67.8.0,<67.9.0", markers = "python_full_version >= \"3.12.0b1\""} +setuptools = {version = "*", markers = "python_full_version >= \"3.12.0\""} [package.extras] compat = ["pytest-benchmark (>=4.0.0,<4.1.0)", "pytest-xdist (>=2.0.0,<2.1.0)"] -lint = ["black (>=23.3.0,<23.4.0)", "isort (>=5.12.0,<5.13.0)", "mypy (>=1.3.0,<1.4.0)", "ruff (>=0.0.275,<0.1.0)"] +lint = ["mypy (>=1.3.0,<1.4.0)", "ruff (>=0.3.3,<0.4.0)"] test = ["pytest (>=7.0,<8.0)", "pytest-cov (>=4.0.0,<4.1.0)"] [[package]] @@ -2205,20 +2193,20 @@ files = [ [[package]] name = "setuptools" -version = "67.8.0" +version = "69.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, - {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, + {file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c"}, + {file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -2357,14 +2345,14 @@ files = [ [[package]] name = "types-aiofiles" -version = "23.2.0.20240310" +version = "23.2.0.20240311" description = "Typing stubs for aiofiles" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "types-aiofiles-23.2.0.20240310.tar.gz", hash = "sha256:6d9fb83caa076a869776479af6727f2bb2a72129c6dea6d7e086a361da16ff09"}, - {file = "types_aiofiles-23.2.0.20240310-py3-none-any.whl", hash = "sha256:bdd8dbb989db119bc0a0120d6eb9741952d2c8f1c0cb05eda513ef276f369682"}, + {file = "types-aiofiles-23.2.0.20240311.tar.gz", hash = "sha256:208e6b090de732739ef74ab8f133c954479c8e77e614f276f9e475a0cc986430"}, + {file = "types_aiofiles-23.2.0.20240311-py3-none-any.whl", hash = "sha256:ed10a8002d88c94220597b77304cf1a1d8cf489c7143fc3ffa2c96488b20fec7"}, ] [[package]] @@ -2441,14 +2429,14 @@ files = [ [[package]] name = "types-requests" -version = "2.31.0.20240310" +version = "2.31.0.20240311" description = "Typing stubs for requests" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "types-requests-2.31.0.20240310.tar.gz", hash = "sha256:8a20171e088a0f7893aac490a5f7f37e9f53e14d6b762c5d55623bea022ee06f"}, - {file = "types_requests-2.31.0.20240310-py3-none-any.whl", hash = "sha256:a4ba49353e3f6b3fdb481ba6f8455917e8bc2a0b62b775d80833ec000508e5dc"}, + {file = "types-requests-2.31.0.20240311.tar.gz", hash = "sha256:b1c1b66abfb7fa79aae09097a811c4aa97130eb8831c60e47aee4ca344731ca5"}, + {file = "types_requests-2.31.0.20240311-py3-none-any.whl", hash = "sha256:47872893d65a38e282ee9f277a4ee50d1b28bd592040df7d1fdaffdf3779937d"}, ] [package.dependencies] @@ -2586,14 +2574,14 @@ watchmedo = ["PyYAML (>=3.10)"] [[package]] name = "wheel" -version = "0.42.0" +version = "0.43.0" description = "A built-package format for Python" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "wheel-0.42.0-py3-none-any.whl", hash = "sha256:177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d"}, - {file = "wheel-0.42.0.tar.gz", hash = "sha256:c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7ceea617a8"}, + {file = "wheel-0.43.0-py3-none-any.whl", hash = "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81"}, + {file = "wheel-0.43.0.tar.gz", hash = "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85"}, ] [package.extras] @@ -2664,19 +2652,19 @@ test = ["gevent (>=20.6.2)"] [[package]] name = "zipp" -version = "3.17.0" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [extras] aiopg = ["aiopg", "psycopg2-binary"] @@ -2691,4 +2679,4 @@ sqlite = ["aiosqlite"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "3b912bdff99c92f4e359315eb4a0a4107e4dc9c5484ba30bd0cea0e10746001b" +content-hash = "44acc5ac9c3f812f1cd60c3fabc82b723f76d4441455da81b79cd9eee40f321f" diff --git a/pyproject.toml b/pyproject.toml index a707a696f..bc5c84610 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,13 +61,6 @@ PyMySQL = { version = "^1.1.0", optional = true } version = ">=3.6.4" optional = true -[tool.poetry.dependencies.typing-extensions] -version = ">=3.7,<=5.0" -python = "<3.8" - -[tool.poetry.dependencies.importlib-metadata] -version = ">=3.1" -python = "<3.8" [tool.poetry.extras] postgresql = ["asyncpg", "psycopg2-binary"] From d8db4681284cee997436af9406acc7dfcd15be17 Mon Sep 17 00:00:00 2001 From: collerek Date: Sat, 23 Mar 2024 19:19:56 +0100 Subject: [PATCH 95/95] fix import reorder --- ormar/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ormar/__init__.py b/ormar/__init__.py index ab399719a..21a07b4a3 100644 --- a/ormar/__init__.py +++ b/ormar/__init__.py @@ -20,6 +20,7 @@ """ +from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I001 from importlib.metadata import version from ormar.decorators import ( # noqa: I100 @@ -73,7 +74,6 @@ # noqa: I100 from ormar.models import ExcludableItems, Extra, Model, OrmarConfig -from ormar.protocols import QuerySetProtocol, RelationProtocol # noqa: I001 from ormar.queryset import OrderAction, QuerySet, and_, or_ from ormar.relations import RelationType from ormar.signals import Signal