This commit is contained in:
collerek
2022-07-19 10:23:38 +02:00
15 changed files with 280 additions and 129 deletions

View File

@ -10,7 +10,7 @@ jobs:
- name: Checkout Master - name: Checkout Master
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Set up Python 3.8 - name: Set up Python 3.8
uses: actions/setup-python@v2 uses: actions/setup-python@v4
with: with:
python-version: '3.8' python-version: '3.8'
- name: Install dependencies - name: Install dependencies

View File

@ -18,7 +18,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2.2.2 uses: actions/setup-python@v4
with: with:
python-version: '3.x' python-version: '3.x'

View File

@ -44,7 +44,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v1 uses: actions/setup-python@v4
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Install dependencies - name: Install dependencies

View File

@ -429,6 +429,17 @@ You can set this parameter by providing `Meta` class `constraints` argument.
To set one column index use [`unique`](../fields/common-parameters.md#index) common parameter. 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. Of course, you can set many columns as indexes with this param but each of them will be a separate index.
#### CheckColumns
You can set this parameter by providing `Meta` class `constraints` argument.
```Python hl_lines="14-17"
--8<-- "../docs_src/models/docs018.py"
```
!!!note
Note that some databases do not actively support check constraints such as MySQL.
### Pydantic configuration ### Pydantic configuration

View File

@ -75,7 +75,7 @@ album = await Album.objects.select_related("tracks").all()
# Python style # Python style
album = await Album.objects.select_related(Album.tracks).all() album = await Album.objects.select_related(Album.tracks).all()
# will return album will all columns tracks # will return album with all columns tracks
``` ```
You can provide a string or a list of strings (or a field/ list of fields) You can provide a string or a list of strings (or a field/ list of fields)

View File

@ -0,0 +1,25 @@
import datetime
import databases
import sqlalchemy
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Course(ormar.Model):
class Meta:
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 = [
ormar.CheckColumns("start_time < end_time", name="date_check"),
]
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
start_date: datetime.date = ormar.Date()
end_date: datetime.date = ormar.Date()

View File

@ -70,6 +70,7 @@ from ormar.fields import (
Time, Time,
UUID, UUID,
UniqueColumns, UniqueColumns,
CheckColumns,
) # noqa: I100 ) # noqa: I100
from ormar.models import ExcludableItems, Extra, Model from ormar.models import ExcludableItems, Extra, Model
from ormar.models.metaclass import ModelMeta from ormar.models.metaclass import ModelMeta
@ -112,6 +113,7 @@ __all__ = [
"UUID", "UUID",
"UniqueColumns", "UniqueColumns",
"IndexColumns", "IndexColumns",
"CheckColumns",
"QuerySetProtocol", "QuerySetProtocol",
"RelationProtocol", "RelationProtocol",
"ModelMeta", "ModelMeta",

View File

@ -5,7 +5,7 @@ as well as relation Fields (ForeignKey, ManyToMany).
Also a definition for custom CHAR based sqlalchemy UUID field Also a definition for custom CHAR based sqlalchemy UUID field
""" """
from ormar.fields.base import BaseField from ormar.fields.base import BaseField
from ormar.fields.constraints import IndexColumns, UniqueColumns from ormar.fields.constraints import IndexColumns, UniqueColumns, CheckColumns
from ormar.fields.foreign_key import ForeignKey, ForeignKeyField from ormar.fields.foreign_key import ForeignKey, ForeignKeyField
from ormar.fields.many_to_many import ManyToMany, ManyToManyField from ormar.fields.many_to_many import ManyToMany, ManyToManyField
from ormar.fields.model_fields import ( from ormar.fields.model_fields import (

View File

@ -1,6 +1,6 @@
from typing import Any from typing import Any
from sqlalchemy import Index, UniqueConstraint from sqlalchemy import Index, UniqueConstraint, CheckConstraint
class UniqueColumns(UniqueConstraint): class UniqueColumns(UniqueConstraint):
@ -20,3 +20,12 @@ class IndexColumns(Index):
Subclass of sqlalchemy.Index. Subclass of sqlalchemy.Index.
Used to avoid importing anything from sqlalchemy by user. Used to avoid importing anything from sqlalchemy by user.
""" """
class CheckColumns(CheckConstraint):
"""
Subclass of sqlalchemy.CheckConstraint.
Used to avoid importing anything from sqlalchemy by user.
Note that some databases do not actively support check constraints such as MySQL.
"""

View File

@ -298,7 +298,7 @@ def populate_meta_sqlalchemy_table_if_required(meta: "ModelMeta") -> None:
def set_constraint_names(meta: "ModelMeta") -> None: def set_constraint_names(meta: "ModelMeta") -> None:
""" """
Populates the names on IndexColumn and UniqueColumns constraints. Populates the names on IndexColumns and UniqueColumns and CheckColumns constraints.
:param meta: Meta class of the Model without sqlalchemy table constructed :param meta: Meta class of the Model without sqlalchemy table constructed
:type meta: Model class Meta :type meta: Model class Meta
@ -317,6 +317,9 @@ def set_constraint_names(meta: "ModelMeta") -> None:
f"ix_{meta.tablename}_" f"ix_{meta.tablename}_"
f'{"_".join([col for col in constraint._pending_colargs])}' 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}"
def update_column_definition( def update_column_definition(

View File

@ -9,6 +9,7 @@ from typing import (
Type, Type,
Union, Union,
cast, cast,
Callable,
) )
import databases import databases
@ -18,6 +19,7 @@ from sqlalchemy.sql.schema import ColumnCollectionConstraint
import ormar # noqa I100 import ormar # noqa I100
import ormar.fields.constraints import ormar.fields.constraints
from ormar.fields.constraints import UniqueColumns, IndexColumns, CheckColumns
from ormar import ModelDefinitionError # noqa I100 from ormar import ModelDefinitionError # noqa I100
from ormar.exceptions import ModelError from ormar.exceptions import ModelError
from ormar.fields import BaseField from ormar.fields import BaseField
@ -186,7 +188,7 @@ def verify_constraint_names(
for column_set in constraints_columns: for column_set in constraints_columns:
if any(x not in old_aliases.values() for x in column_set): if any(x not in old_aliases.values() for x in column_set):
raise ModelDefinitionError( raise ModelDefinitionError(
f"Unique columns constraint " f"Column constraints "
f"{column_set} " f"{column_set} "
f"has column names " f"has column names "
f"that are not in the model fields." f"that are not in the model fields."
@ -195,6 +197,33 @@ def verify_constraint_names(
) )
def get_constraint_copy(
constraint: ColumnCollectionConstraint,
) -> Union[UniqueColumns, IndexColumns, CheckColumns]:
"""
Copy the constraint and unpacking it's values
:raises ValueError: if non subclass of ColumnCollectionConstraint
:param value: an instance of the ColumnCollectionConstraint class
:type value: Instance of ColumnCollectionConstraint child
:return: copy ColumnCollectionConstraint ormar constraints
:rtype: Union[UniqueColumns, IndexColumns, CheckColumns]
"""
constraints = {
sqlalchemy.UniqueConstraint: lambda x: UniqueColumns(*x._pending_colargs),
sqlalchemy.Index: lambda x: IndexColumns(*x._pending_colargs),
sqlalchemy.CheckConstraint: lambda x: CheckColumns(x.sqltext),
}
checks = (key if isinstance(constraint, key) else None for key in constraints)
target_class = next((target for target in checks if target is not None), None)
constructor: Optional[Callable] = constraints.get(target_class)
if not constructor:
raise ValueError(f"{constraint} must be a ColumnCollectionMixin!")
return constructor(constraint)
def update_attrs_from_base_meta( # noqa: CCR001 def update_attrs_from_base_meta( # noqa: CCR001
base_class: "Model", attrs: Dict, model_fields: Dict base_class: "Model", attrs: Dict, model_fields: Dict
) -> None: ) -> None:
@ -222,10 +251,7 @@ def update_attrs_from_base_meta( # noqa: CCR001
model_fields=model_fields, model_fields=model_fields,
parent_value=parent_value, parent_value=parent_value,
) )
parent_value = [ parent_value = [get_constraint_copy(value) for value in parent_value]
ormar.fields.constraints.UniqueColumns(*x._pending_colargs)
for x in parent_value
]
if isinstance(current_value, list): if isinstance(current_value, list):
current_value.extend(parent_value) current_value.extend(parent_value)
else: else:

215
poetry.lock generated
View File

@ -80,7 +80,7 @@ typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""}
[[package]] [[package]]
name = "asyncpg" name = "asyncpg"
version = "0.25.0" version = "0.26.0"
description = "An asyncio PostgreSQL driver" description = "An asyncio PostgreSQL driver"
category = "main" category = "main"
optional = true optional = true
@ -260,7 +260,7 @@ toml = ["tomli"]
[[package]] [[package]]
name = "cryptography" name = "cryptography"
version = "37.0.3" version = "37.0.4"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
category = "main" category = "main"
optional = true optional = true
@ -673,7 +673,7 @@ mkdocs = ">=1.1"
[[package]] [[package]]
name = "mkdocs-gen-files" name = "mkdocs-gen-files"
version = "0.3.4" version = "0.3.5"
description = "MkDocs plugin to programmatically generate documentation pages during the build" description = "MkDocs plugin to programmatically generate documentation pages during the build"
category = "dev" category = "dev"
optional = false optional = false
@ -820,7 +820,7 @@ python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*
[[package]] [[package]]
name = "orjson" name = "orjson"
version = "3.7.6" version = "3.7.7"
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
category = "main" category = "main"
optional = true optional = true
@ -882,7 +882,7 @@ testing = ["pytest", "pytest-benchmark"]
[[package]] [[package]]
name = "pre-commit" name = "pre-commit"
version = "2.19.0" version = "2.20.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks." description = "A framework for managing and maintaining multi-language pre-commit hooks."
category = "dev" category = "dev"
optional = false optional = false
@ -1214,7 +1214,7 @@ python-versions = ">=3.6"
[[package]] [[package]]
name = "types-aiofiles" name = "types-aiofiles"
version = "0.8.8" version = "0.8.9"
description = "Typing stubs for aiofiles" description = "Typing stubs for aiofiles"
category = "dev" category = "dev"
optional = false optional = false
@ -1270,7 +1270,7 @@ python-versions = "*"
[[package]] [[package]]
name = "types-requests" name = "types-requests"
version = "2.28.0" version = "2.28.2"
description = "Typing stubs for requests" description = "Typing stubs for requests"
category = "dev" category = "dev"
optional = false optional = false
@ -1281,7 +1281,7 @@ types-urllib3 = "<1.27"
[[package]] [[package]]
name = "types-toml" name = "types-toml"
version = "0.10.7" version = "0.10.8"
description = "Typing stubs for toml" description = "Typing stubs for toml"
category = "dev" category = "dev"
optional = false optional = false
@ -1289,7 +1289,7 @@ python-versions = "*"
[[package]] [[package]]
name = "types-ujson" name = "types-ujson"
version = "5.3.1" version = "5.4.0"
description = "Typing stubs for ujson" description = "Typing stubs for ujson"
category = "dev" category = "dev"
optional = false optional = false
@ -1390,7 +1390,7 @@ sqlite = ["aiosqlite"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7.0" python-versions = "^3.7.0"
content-hash = "d6f5edac5bfb5705f47aa235e19f8f228d9d604206ac587c4ef362c6aea4c3de" content-hash = "be670ab27974c6e50b4dfeedaabeedd48a62064659d59bad6ef22b336907614d"
[metadata.files] [metadata.files]
aiomysql = [ aiomysql = [
@ -1418,32 +1418,32 @@ async-timeout = [
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
] ]
asyncpg = [ asyncpg = [
{file = "asyncpg-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf5e3408a14a17d480f36ebaf0401a12ff6ae5457fdf45e4e2775c51cc9517d3"}, {file = "asyncpg-0.26.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ed3880b3aec8bda90548218fe0914d251d641f798382eda39a17abfc4910af0"},
{file = "asyncpg-0.25.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2bc197fc4aca2fd24f60241057998124012469d2e414aed3f992579db0c88e3a"}, {file = "asyncpg-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5bd99ee7a00e87df97b804f178f31086e88c8106aca9703b1d7be5078999e68"},
{file = "asyncpg-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a70783f6ffa34cc7dd2de20a873181414a34fd35a4a208a1f1a7f9f695e4ec4"}, {file = "asyncpg-0.26.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:868a71704262834065ca7113d80b1f679609e2df77d837747e3d92150dd5a39b"},
{file = "asyncpg-0.25.0-cp310-cp310-win32.whl", hash = "sha256:43cde84e996a3afe75f325a68300093425c2f47d340c0fc8912765cf24a1c095"}, {file = "asyncpg-0.26.0-cp310-cp310-win32.whl", hash = "sha256:838e4acd72da370ad07243898e886e93d3c0c9413f4444d600ba60a5cc206014"},
{file = "asyncpg-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:56d88d7ef4341412cd9c68efba323a4519c916979ba91b95d4c08799d2ff0c09"}, {file = "asyncpg-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:a254d09a3a989cc1839ba2c34448b879cdd017b528a0cda142c92fbb6c13d957"},
{file = "asyncpg-0.25.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a84d30e6f850bac0876990bcd207362778e2208df0bee8be8da9f1558255e634"}, {file = "asyncpg-0.26.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3ecbe8ed3af4c739addbfbd78f7752866cce2c4e9cc3f953556e4960349ae360"},
{file = "asyncpg-0.25.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:beaecc52ad39614f6ca2e48c3ca15d56e24a2c15cbfdcb764a4320cc45f02fd5"}, {file = "asyncpg-0.26.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ce7d8c0ab4639bbf872439eba86ef62dd030b245ad0e17c8c675d93d7a6b2d"},
{file = "asyncpg-0.25.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:6f8f5fc975246eda83da8031a14004b9197f510c41511018e7b1bedde6968e92"}, {file = "asyncpg-0.26.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7129bd809990fd119e8b2b9982e80be7712bb6041cd082be3e415e60e5e2e98f"},
{file = "asyncpg-0.25.0-cp36-cp36m-win32.whl", hash = "sha256:ddb4c3263a8d63dcde3d2c4ac1c25206bfeb31fa83bd70fd539e10f87739dee4"}, {file = "asyncpg-0.26.0-cp36-cp36m-win32.whl", hash = "sha256:03f44926fa7ff7ccd59e98f05c7e227e9de15332a7da5bbcef3654bf468ee597"},
{file = "asyncpg-0.25.0-cp36-cp36m-win_amd64.whl", hash = "sha256:bf6dc9b55b9113f39eaa2057337ce3f9ef7de99a053b8a16360395ce588925cd"}, {file = "asyncpg-0.26.0-cp36-cp36m-win_amd64.whl", hash = "sha256:b1f7b173af649b85126429e11a628d01a5b75973d2a55d64dba19ad8f0e9f904"},
{file = "asyncpg-0.25.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:acb311722352152936e58a8ee3c5b8e791b24e84cd7d777c414ff05b3530ca68"}, {file = "asyncpg-0.26.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe056fd22fc6ed5c1ab353b6510808409566daac4e6f105e2043797f17b8dad"},
{file = "asyncpg-0.25.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0a61fb196ce4dae2f2fa26eb20a778db21bbee484d2e798cb3cc988de13bdd1b"}, {file = "asyncpg-0.26.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d96cf93e01df9fb03cef5f62346587805e6c0ca6f654c23b8d35315bdc69af59"},
{file = "asyncpg-0.25.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2633331cbc8429030b4f20f712f8d0fbba57fa8555ee9b2f45f981b81328b256"}, {file = "asyncpg-0.26.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:235205b60d4d014921f7b1cdca0e19669a9a8978f7606b3eb8237ca95f8e716e"},
{file = "asyncpg-0.25.0-cp37-cp37m-win32.whl", hash = "sha256:863d36eba4a7caa853fd7d83fad5fd5306f050cc2fe6e54fbe10cdb30420e5e9"}, {file = "asyncpg-0.26.0-cp37-cp37m-win32.whl", hash = "sha256:0de408626cfc811ef04f372debfcdd5e4ab5aeb358f2ff14d1bdc246ed6272b5"},
{file = "asyncpg-0.25.0-cp37-cp37m-win_amd64.whl", hash = "sha256:fe471ccd915b739ca65e2e4dbd92a11b44a5b37f2e38f70827a1c147dafe0fa8"}, {file = "asyncpg-0.26.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f92d501bf213b16fabad4fbb0061398d2bceae30ddc228e7314c28dcc6641b79"},
{file = "asyncpg-0.25.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:72a1e12ea0cf7c1e02794b697e3ca967b2360eaa2ce5d4bfdd8604ec2d6b774b"}, {file = "asyncpg-0.26.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9acb22a7b6bcca0d80982dce3d67f267d43e960544fb5dd934fd3abe20c48014"},
{file = "asyncpg-0.25.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4327f691b1bdb222df27841938b3e04c14068166b3a97491bec2cb982f49f03e"}, {file = "asyncpg-0.26.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e550d8185f2c4725c1e8d3c555fe668b41bd092143012ddcc5343889e1c2a13d"},
{file = "asyncpg-0.25.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:739bbd7f89a2b2f6bc44cb8bf967dab12c5bc714fcbe96e68d512be45ecdf962"}, {file = "asyncpg-0.26.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:050e339694f8c5d9aebcf326ca26f6622ef23963a6a3a4f97aeefc743954afd5"},
{file = "asyncpg-0.25.0-cp38-cp38-win32.whl", hash = "sha256:18d49e2d93a7139a2fdbd113e320cc47075049997268a61bfbe0dde680c55471"}, {file = "asyncpg-0.26.0-cp38-cp38-win32.whl", hash = "sha256:b0c3f39ebfac06848ba3f1e280cb1fada7cc1229538e3dad3146e8d1f9deb92a"},
{file = "asyncpg-0.25.0-cp38-cp38-win_amd64.whl", hash = "sha256:191fe6341385b7fdea7dbdcf47fd6db3fd198827dcc1f2b228476d13c05a03c6"}, {file = "asyncpg-0.26.0-cp38-cp38-win_amd64.whl", hash = "sha256:49fc7220334cc31d14866a0b77a575d6a5945c0fa3bb67f17304e8b838e2a02b"},
{file = "asyncpg-0.25.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:52fab7f1b2c29e187dd8781fce896249500cf055b63471ad66332e537e9b5f7e"}, {file = "asyncpg-0.26.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d156e53b329e187e2dbfca8c28c999210045c45ef22a200b50de9b9e520c2694"},
{file = "asyncpg-0.25.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a738f1b2876f30d710d3dc1e7858160a0afe1603ba16bf5f391f5316eb0ed855"}, {file = "asyncpg-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b4051012ca75defa9a1dc6b78185ca58cdc3a247187eb76a6bcf55dfaa2fad4"},
{file = "asyncpg-0.25.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4105f57ad1e8fbc8b1e535d8fcefa6ce6c71081228f08680c6dea24384ff0e"}, {file = "asyncpg-0.26.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d60f15a0ac18c54a6ca6507c28599c06e2e87a0901e7b548f15243d71905b18"},
{file = "asyncpg-0.25.0-cp39-cp39-win32.whl", hash = "sha256:f55918ded7b85723a5eaeb34e86e7b9280d4474be67df853ab5a7fa0cc7c6bf2"}, {file = "asyncpg-0.26.0-cp39-cp39-win32.whl", hash = "sha256:ede1a3a2c377fe12a3930f4b4dd5340e8b32929541d5db027a21816852723438"},
{file = "asyncpg-0.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:649e2966d98cc48d0646d9a4e29abecd8b59d38d55c256d5c857f6b27b7407ac"}, {file = "asyncpg-0.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:8e1e79f0253cbd51fc43c4d0ce8804e46ee71f6c173fdc75606662ad18756b52"},
{file = "asyncpg-0.25.0.tar.gz", hash = "sha256:63f8e6a69733b285497c2855464a34de657f2cccd25aeaeeb5071872e9382540"}, {file = "asyncpg-0.26.0.tar.gz", hash = "sha256:77e684a24fee17ba3e487ca982d0259ed17bae1af68006f4cf284b23ba20ea2c"},
] ]
atomicwrites = [ atomicwrites = [
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
@ -1624,28 +1624,28 @@ coverage = [
{file = "coverage-6.4.1.tar.gz", hash = "sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c"}, {file = "coverage-6.4.1.tar.gz", hash = "sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c"},
] ]
cryptography = [ cryptography = [
{file = "cryptography-37.0.3-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:d10413d493e98075060d3e62e5826de372912ea653ccc948f3c41b21ddca087f"}, {file = "cryptography-37.0.4-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884"},
{file = "cryptography-37.0.3-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:cd64147ff16506632893ceb2569624b48c84daa3ba4d89695f7c7bc24188eee9"}, {file = "cryptography-37.0.4-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6"},
{file = "cryptography-37.0.3-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:17c74f7d9e9e9bb7e84521243695c1b4bdc3a0e44ca764e6bcf8f05f3de3d0df"}, {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046"},
{file = "cryptography-37.0.3-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:0713bee6c8077786c56bdec9c5d3f099d40d2c862ff3200416f6862e9dd63156"}, {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5"},
{file = "cryptography-37.0.3-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9c2008417741cdfbe945ef2d16b7b7ba0790886a0b49e1de533acf93eb66ed6"}, {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b"},
{file = "cryptography-37.0.3-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:646905ff7a712e415bf0d0f214e0eb669dd2257c4d7a27db1e8baec5d2a1d55f"}, {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8"},
{file = "cryptography-37.0.3-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:dcafadb5a06cb7a6bb49fb4c1de7414ee2f8c8e12b047606d97c3175d690f582"}, {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280"},
{file = "cryptography-37.0.3-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0b4bfc5ccfe4e5c7de535670680398fed4a0bbc5dfd52b3a295baad42230abdf"}, {file = "cryptography-37.0.4-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3"},
{file = "cryptography-37.0.3-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a03dbc0d8ce8c1146c177cd0e3a66ea106f36733fb1b997ea4d051f8a68539ff"}, {file = "cryptography-37.0.4-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59"},
{file = "cryptography-37.0.3-cp36-abi3-win32.whl", hash = "sha256:190a24c14e91c1fa3101069aac7e77d11c5a73911c3904128367f52946bbb6fd"}, {file = "cryptography-37.0.4-cp36-abi3-win32.whl", hash = "sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157"},
{file = "cryptography-37.0.3-cp36-abi3-win_amd64.whl", hash = "sha256:b05c5478524deb7a019e240f2a970040c4b0f01f58f0425e6262c96b126c6a3e"}, {file = "cryptography-37.0.4-cp36-abi3-win_amd64.whl", hash = "sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327"},
{file = "cryptography-37.0.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891ed8312840fd43e0696468a6520a582a033c0109f7b14b96067bfe1123226b"}, {file = "cryptography-37.0.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b"},
{file = "cryptography-37.0.3-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:30d6aabf623a01affc7c0824936c3dde6590076b61f5dd299df3cc2c75fc5915"}, {file = "cryptography-37.0.4-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9"},
{file = "cryptography-37.0.3-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:31a7c1f1c2551f013d4294d06e22848e2ccd77825f0987cba3239df6ebf7b020"}, {file = "cryptography-37.0.4-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67"},
{file = "cryptography-37.0.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a94fd1ff80001cb97add71d07f596d8b865b716f25ef501183e0e199390e50d3"}, {file = "cryptography-37.0.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d"},
{file = "cryptography-37.0.3-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:8a85dbcc770256918b40c2f40bd3ffd3b2ae45b0cf19068b561db8f8d61bf492"}, {file = "cryptography-37.0.4-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282"},
{file = "cryptography-37.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:773d5b5f2e2bd2c7cbb1bd24902ad41283c88b9dd463a0f82adc9a2870d9d066"}, {file = "cryptography-37.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa"},
{file = "cryptography-37.0.3-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0f9193428a55a4347af2d4fd8141a2002dedbcc26487e67fd2ae19f977ee8afc"}, {file = "cryptography-37.0.4-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441"},
{file = "cryptography-37.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bf652c73e8f7c32a3f92f7184bf7f9106dacdf5ef59c3c3683d7dae2c4972fb"}, {file = "cryptography-37.0.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596"},
{file = "cryptography-37.0.3-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:c3c8b1ad2c266fdf7adc041cc4156d6a3d14db93de2f81b26a5af97ef3f209e5"}, {file = "cryptography-37.0.4-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a"},
{file = "cryptography-37.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2383d6c3088e863304c37c65cd2ea404b7fbb4886823eab1d74137cc27f3d2ee"}, {file = "cryptography-37.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab"},
{file = "cryptography-37.0.3.tar.gz", hash = "sha256:ae430d51c67ac638dfbb42edf56c669ca9c74744f4d225ad11c6f3d355858187"}, {file = "cryptography-37.0.4.tar.gz", hash = "sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82"},
] ]
databases = [ databases = [
{file = "databases-0.6.0-py3-none-any.whl", hash = "sha256:c36468d9e00f47a825669a73158e6745e0401a169186fdefbb2fb7d43276320a"}, {file = "databases-0.6.0-py3-none-any.whl", hash = "sha256:c36468d9e00f47a825669a73158e6745e0401a169186fdefbb2fb7d43276320a"},
@ -1866,8 +1866,8 @@ mkdocs-autorefs = [
{file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"}, {file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"},
] ]
mkdocs-gen-files = [ mkdocs-gen-files = [
{file = "mkdocs-gen-files-0.3.4.tar.gz", hash = "sha256:c69188486bdc1e74bd2b9b7ebbde9f9eb21052ae7762f1b35420cfbfc6d7122e"}, {file = "mkdocs-gen-files-0.3.5.tar.gz", hash = "sha256:d90d9e1676531a0bb96b1287dc28aa41162986de4dc3c00400214724761ff6ef"},
{file = "mkdocs_gen_files-0.3.4-py3-none-any.whl", hash = "sha256:07f43245c87a03cfb03884e767655c2a61def24d07e47fb3a8d26b1581524d6a"}, {file = "mkdocs_gen_files-0.3.5-py3-none-any.whl", hash = "sha256:69562fddc662482e8f54a00a8b4ede5166ad5384ae4dbb0469f1f338ef3285ca"},
] ]
mkdocs-literate-nav = [ mkdocs-literate-nav = [
{file = "mkdocs-literate-nav-0.4.1.tar.gz", hash = "sha256:9efe26b662f2f901cae5807bfd51446d30ea7e033c2bc43a15d6282c7dfac1ab"}, {file = "mkdocs-literate-nav-0.4.1.tar.gz", hash = "sha256:9efe26b662f2f901cae5807bfd51446d30ea7e033c2bc43a15d6282c7dfac1ab"},
@ -1940,43 +1940,44 @@ nodeenv = [
{file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"},
] ]
orjson = [ orjson = [
{file = "orjson-3.7.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:381a68122327d08a5891864b64c932eb9238d3bfc58c859664b4ddd9b10f01cd"}, {file = "orjson-3.7.7-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:092fde5b1768ca68af0d3764746e93b4b7200050fdd9c1ea044fd106e2379951"},
{file = "orjson-3.7.6-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:86c6755d0c66fa8ea8d925e745f3aea6647e77a4691a4c4feb8ef776046dc268"}, {file = "orjson-3.7.7-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:313bcab8cd59d61e12bbf76a9b5f3eaf50848e3fb370a54f712ad3e3e0a48165"},
{file = "orjson-3.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd64c60fe9dbb9cd1f783ca0a721a5936b11db7196dd4692dae05bda6e49c82f"}, {file = "orjson-3.7.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f80825fa7a48c4abcd636d3c182a71ad1cb548db66b8aafad50dfd328c29ae0"},
{file = "orjson-3.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:276011c420f09384356d5a66fa8d5f3bde052df3f147e59ea724845f1fd02fdf"}, {file = "orjson-3.7.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead2c1dce61c2e3bad31af48c2dccbbc23c55bbe70870af437203a7c4b229bae"},
{file = "orjson-3.7.6-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b522746bbf4d9fbfe4be1137c093979a335e6d763d0928014450684229ecce75"}, {file = "orjson-3.7.7-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d8f1aa7fd08f001b5f13d0c8c862609bb7de7291b256630f97590eb7c78d2dda"},
{file = "orjson-3.7.6-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7dcf250c023cdc584e83f9df15c7c942c1582cd90ff44debd46ee1444721ac7d"}, {file = "orjson-3.7.7-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6e5ea0fcf3452cd19ad34b37ca6279c4395b859c77fe1cf7e26d31a3e6ebafd5"},
{file = "orjson-3.7.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ede049d29dcc32c111a954b3625a3f135559c00110793c3808a7299caafae614"}, {file = "orjson-3.7.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70cffd48faafabdd7e42f35e38731c43200d525fdbabc587b1e2aa731d182f85"},
{file = "orjson-3.7.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:da1ec307834bbcf9fc8afcac7abbcb391e9bda8fc22f004ad9ee8a57fae4c45e"}, {file = "orjson-3.7.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aee6715db93b3d743adc69f55ed20df6a782b5e354d26a7817e507e2bd6d2231"},
{file = "orjson-3.7.6-cp310-none-win_amd64.whl", hash = "sha256:5c231c4164a4c08c3f6d6b84baa4b2c80ea426937ebd5185ade6ab010bf1932f"}, {file = "orjson-3.7.7-cp310-none-win_amd64.whl", hash = "sha256:d9af18e8200b500585627414ec7b0806b5b569a318d6c84447afb02e7eae5bfa"},
{file = "orjson-3.7.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:fe885312ed83e44de0a6a83a8d00e40ef2d3c1e90b2ac9767897b393c9db3e65"}, {file = "orjson-3.7.7-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:5c8141895c8b0a8b4d0bc1879d1c1e3ec3f7d7e29e0bd8a0146ef3f9cf13c325"},
{file = "orjson-3.7.6-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:cbf04c629518075b00953832b8fb28c0a9538d6867f29f1259a5a8b357e7303b"}, {file = "orjson-3.7.7-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:5f20d0d48335262ca3695f98599446bf5ca8825193d1f4bf6eb08fb0c414befa"},
{file = "orjson-3.7.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd2acae5824fabe130b38dbdb194ed1f4ad48067e577ae9b937f92086e751933"}, {file = "orjson-3.7.7-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:6fbf29bb7897d345bd0120c466cd923c70a5d661144221457cbed637f4c93d1b"},
{file = "orjson-3.7.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d296d58c4112021938dead91a8af369daaf22a21d9a468cdae412cd6f3071c5b"}, {file = "orjson-3.7.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c43fd0317a7114e617f5b8aefd0d0a61b387927a1914b79ebd0d1235c658f5b"},
{file = "orjson-3.7.6-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:b374302846fd1646339e599a55909bc69820ab85b2f88f32d5d7c950d165c6e0"}, {file = "orjson-3.7.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9451779dba8546962bc02ce2aeed9de6e069f7101f8db2784beaf71ede4dd0"},
{file = "orjson-3.7.6-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:fa22f898f6f677f66b03c8267bc61a86305ddc1092f4ca2fadc0786d793ad421"}, {file = "orjson-3.7.7-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:e8bfad95df150d95ca67a4484d9f56e2bd0a932a5eb4635bbb5cd45130ca9251"},
{file = "orjson-3.7.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d7981d69ea530d75bbe4102957bdb32bd4c07149d2a91c815579a3d95eed1172"}, {file = "orjson-3.7.7-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:ce3acc906a6aa7923bc7c78472196b2b7cf7c160aff01946984d51fcde9e9483"},
{file = "orjson-3.7.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b63ff3b8d9807f7727efaa5d5c16b0c9408c4a29bf209cc559151bf35f3b9ad9"}, {file = "orjson-3.7.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c1e8489d50bb0cffb5ccb70c3459f79dee1aeb997abfd97751d3862b32bce412"},
{file = "orjson-3.7.6-cp37-none-win_amd64.whl", hash = "sha256:cb676e1fd90685dce0a28fee9c2ccfdddbb08095f3d527ee78bf9c80a7bf2b3a"}, {file = "orjson-3.7.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:891c0f2cb44beafa911cf7e15165dee8b8acaa5b48a75abaf37d529e1de68344"},
{file = "orjson-3.7.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:1e3a9c20bbbfdcb49d0926da12ab8b1f62c540c15f986a207fc34205bc9f8f88"}, {file = "orjson-3.7.7-cp37-none-win_amd64.whl", hash = "sha256:6a743e05de78758f9ff81a4e705e6226b06a5f8abba63b39cb0f56926c2045c5"},
{file = "orjson-3.7.6-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:4526ac50bd38185066debacce3a188d93f98710448c6ec3695968397e6a9b1b5"}, {file = "orjson-3.7.7-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:b6a6d00e917e1844d3a9b6ed68d31f824d98e1e4a3578618dd146db58b5d901b"},
{file = "orjson-3.7.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9d422524d6e83b8868daf401a184bca99a1c9d584c7532c3f1a948b930fcb7f"}, {file = "orjson-3.7.7-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:3e9b1f19b408199af4d4ad590f6935ba77342a3fe1d64cbbfe428025a03a2405"},
{file = "orjson-3.7.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3f31559bd06501eaedbfa525723ac08f01b585c0f83c2621f7d6dabde5e4f99"}, {file = "orjson-3.7.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6340e57fece4fa0eebd1e5c48e2c844b329491d97bfe6843149eb45365ff837a"},
{file = "orjson-3.7.6-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:09d71813fb0427e5564ceff5b563dcc974c6780cd1ed6abfabf57f58e66f9a8b"}, {file = "orjson-3.7.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ff90b571023787dcbb504a1695ad137149df30d213128b1aa02fc82dd12a526"},
{file = "orjson-3.7.6-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f251892557d3edd28743af135e757cae79c7c7a05383a71d5053e7cc26214af0"}, {file = "orjson-3.7.7-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:ea3eaa8823bbbaae7af9669ca68b0e0bd794ee0938900d73f5f321fb13bb5ab5"},
{file = "orjson-3.7.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5f26226f1f2408d426810c18848acf6a1556a54fd75a62569c3f18b5a380c571"}, {file = "orjson-3.7.7-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:8da26f1fd335e466e79779571326679b179bb7cf3cce9750bf9c1077e9298a6f"},
{file = "orjson-3.7.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3eaea4dd4eea85aefeec64ba463510b078009ad574dc00f9c504f262b8e1b7f3"}, {file = "orjson-3.7.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3f9fbf760c6612d08a4ea873e4fab1e657f826834deda58c2ba1406ef150b1b6"},
{file = "orjson-3.7.6-cp38-none-win_amd64.whl", hash = "sha256:bc3dd9d15d678a67ff3e28ce2b87f3255c36a7cd28642b7bea293e20cf56aa49"}, {file = "orjson-3.7.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ee2cd3ac6283832d93085910df8367a469bd9dbfafeb8d4dc8c5cc8648bf965c"},
{file = "orjson-3.7.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:588f6294dcd6278edb57504cdb8564ca0bab6ea4caa92a0ad4a494f8293ce1b5"}, {file = "orjson-3.7.7-cp38-none-win_amd64.whl", hash = "sha256:0033c7279f0ffa2720d72a6234a1d22c86c13bf5217a99c5ba523a0aebb27b75"},
{file = "orjson-3.7.6-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:2961734ebd3d6598939d56bcb8a2e8dc28b2dd2ec91c7aad32efbb1b44e7fde0"}, {file = "orjson-3.7.7-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:559f40a91bfde23137e107f2f8baaf0bef35e066d0b35dcf4e1dac8bc83a05b3"},
{file = "orjson-3.7.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:255026bbcd78a366e03e941a6d8d55c5017632f43729a2b70b9e133da8cd6160"}, {file = "orjson-3.7.7-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9f7f420ab7efde90c7277e92dccf217b4bac628b044fdc857888cdba23126214"},
{file = "orjson-3.7.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52f3dacd8edf333b661d94548f5bb525c725f9ab39621e4f6b0ad086eb50e5a8"}, {file = "orjson-3.7.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba48e06659c43ed6658f203893b74b4e8392231959bcb2421fdde39eca62520c"},
{file = "orjson-3.7.6-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:62e26eeccffd07b55fa35241256e268b7b8e45167dae4186c445bb0fbe14b5e4"}, {file = "orjson-3.7.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a34002a6b6eb105d3ac493368f0a8911ab8e5f005282d43cc75912bbbdf50734"},
{file = "orjson-3.7.6-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:79fd55f59bd9c2ce40f2dacc7395b01ec9e6d92bdbcca2e174d2d4790ea9993e"}, {file = "orjson-3.7.7-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:dbf716120886776706781c2c05ebbc254355e384bfe387b76ca07ee97da6fbfc"},
{file = "orjson-3.7.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3e4d50095fe9a707f4b9e2b257da00e6501326fdfb0f95f51d0d26f21bb5dc66"}, {file = "orjson-3.7.7-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:f0c512efeee1fb94426b1e4c64f07c4af5eec08b96cf4835c3a05ad395e0b83a"},
{file = "orjson-3.7.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5a40f921972224e8365a3c812415653e602a4892eb658ad5f2df0d7c76bbce76"}, {file = "orjson-3.7.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:657ce6d735dc3a6fba5043d831e769698db849915d581dd4d1e62fcc2eaed876"},
{file = "orjson-3.7.6-cp39-none-win_amd64.whl", hash = "sha256:fe21819312f20e3a9167bbef4818cdde0bb2c7049a0f56acd44225255efb45e9"}, {file = "orjson-3.7.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c30ad18fad795690527b030cfed3e8402ebe3a15e7a1a779a00acc0b3587e89"},
{file = "orjson-3.7.6.tar.gz", hash = "sha256:520a6c37b349b5a41c2f14829ac23418f1187ce09d1088cb6100b6c856f7bafb"}, {file = "orjson-3.7.7-cp39-none-win_amd64.whl", hash = "sha256:ea0f6da9089e155acf234c0cd0883f84812547174be8d0fef478bce2b00bd6f9"},
{file = "orjson-3.7.7.tar.gz", hash = "sha256:2850cf49537c246000f5f89555d6fb7042bb4612214605a60bea89cbe0add213"},
] ]
packaging = [ packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
@ -1999,8 +2000,8 @@ pluggy = [
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
] ]
pre-commit = [ pre-commit = [
{file = "pre_commit-2.19.0-py2.py3-none-any.whl", hash = "sha256:10c62741aa5704faea2ad69cb550ca78082efe5697d6f04e5710c3c229afdd10"}, {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"},
{file = "pre_commit-2.19.0.tar.gz", hash = "sha256:4233a1e38621c87d9dda9808c6606d7e7ba0e087cd56d3fe03202a01d2919615"}, {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"},
] ]
psycopg2-binary = [ psycopg2-binary = [
{file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"}, {file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"},
@ -2286,8 +2287,8 @@ typed-ast = [
{file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"},
] ]
types-aiofiles = [ types-aiofiles = [
{file = "types-aiofiles-0.8.8.tar.gz", hash = "sha256:62942901b44dd8fb14b5581e8389fa0fe5c03b8aef7a1f86ac08e7b550d7dc11"}, {file = "types-aiofiles-0.8.9.tar.gz", hash = "sha256:ed4e35cee4cd7b51da6e6764405ff4d7cf3bd83e0db9db85ef09878e16fe3125"},
{file = "types_aiofiles-0.8.8-py3-none-any.whl", hash = "sha256:64846425bc267beec45ddf50b14fb532e6612b9d74c976761cc5e1c47a88a06b"}, {file = "types_aiofiles-0.8.9-py3-none-any.whl", hash = "sha256:ab1e27ecb3efe73e3c86d22f327ce00587743b900560a5348d321bc91bcd7c21"},
] ]
types-cryptography = [ types-cryptography = [
{file = "types-cryptography-3.3.21.tar.gz", hash = "sha256:ad1b9c63159c009f8676c7e41a4d595dfb96e8c03affa2e693e1617908bb409e"}, {file = "types-cryptography-3.3.21.tar.gz", hash = "sha256:ad1b9c63159c009f8676c7e41a4d595dfb96e8c03affa2e693e1617908bb409e"},
@ -2314,16 +2315,16 @@ types-pymysql = [
{file = "types_PyMySQL-1.0.19-py3-none-any.whl", hash = "sha256:fc43dceda3f3fc4ac388db7dd57b157c13d94cb84e30cca4848df590c314bf68"}, {file = "types_PyMySQL-1.0.19-py3-none-any.whl", hash = "sha256:fc43dceda3f3fc4ac388db7dd57b157c13d94cb84e30cca4848df590c314bf68"},
] ]
types-requests = [ types-requests = [
{file = "types-requests-2.28.0.tar.gz", hash = "sha256:9863d16dfbb3fa55dcda64fa3b989e76e8859033b26c1e1623e30465cfe294d3"}, {file = "types-requests-2.28.2.tar.gz", hash = "sha256:398f88cd9302c796cb63d1021af2a1fb7ae507741a3d508edf8e0746d8c16a04"},
{file = "types_requests-2.28.0-py3-none-any.whl", hash = "sha256:85383b4ef0535f639c3f06c5bbb6494bbf59570c4cd88bbcf540f0b2ac1b49ab"}, {file = "types_requests-2.28.2-py3-none-any.whl", hash = "sha256:c164696bfdce0123901165c5f097a6cc4f6326268c65815d4b6a57eacfec5e81"},
] ]
types-toml = [ types-toml = [
{file = "types-toml-0.10.7.tar.gz", hash = "sha256:a567fe2614b177d537ad99a661adc9bfc8c55a46f95e66370a4ed2dd171335f9"}, {file = "types-toml-0.10.8.tar.gz", hash = "sha256:b7e7ea572308b1030dc86c3ba825c5210814c2825612ec679eb7814f8dd9295a"},
{file = "types_toml-0.10.7-py3-none-any.whl", hash = "sha256:05a8da4bfde2f1ee60e90c7071c063b461f74c63a9c3c1099470c08d6fa58615"}, {file = "types_toml-0.10.8-py3-none-any.whl", hash = "sha256:8300fd093e5829eb9c1fba69cee38130347d4b74ddf32d0a7df650ae55c2b599"},
] ]
types-ujson = [ types-ujson = [
{file = "types-ujson-5.3.1.tar.gz", hash = "sha256:64698711b7b5e21a270213aa491ae3a4e2d75406e9536b1d998c259efb8aa416"}, {file = "types-ujson-5.4.0.tar.gz", hash = "sha256:c6124cadc36e565a90b01213aeec3447f571d9793d177e1653146a3867c81beb"},
{file = "types_ujson-5.3.1-py3-none-any.whl", hash = "sha256:09a9f1c1b511423c37cda6247492f93bde1157141b5ecff9509a28c920e8c0e4"}, {file = "types_ujson-5.4.0-py3-none-any.whl", hash = "sha256:551bb93e13f010cdc17ccc97cab0e44b7891d54acb8977f0ab64fcb9d6e44cc2"},
] ]
types-urllib3 = [ types-urllib3 = [
{file = "types-urllib3-1.26.15.tar.gz", hash = "sha256:c89283541ef92e344b7f59f83ea9b5a295b16366ceee3f25ecfc5593c79f794e"}, {file = "types-urllib3-1.26.15.tar.gz", hash = "sha256:c89283541ef92e344b7f59f83ea9b5a295b16366ceee3f25ecfc5593c79f794e"},

View File

@ -50,7 +50,7 @@ cryptography = { version = ">=35,<38", optional = true }
aiosqlite = { version = "^0.17.0", optional = true } aiosqlite = { version = "^0.17.0", optional = true }
aiomysql = { version = ">=0.0.21,<0.0.23", optional = true } aiomysql = { version = ">=0.0.21,<0.0.23", optional = true }
aiopg = { version = "^1.3.3", optional = true } aiopg = { version = "^1.3.3", optional = true }
asyncpg = { version = ">=0.24,<0.26", optional = true } asyncpg = { version = ">=0.24,<0.27", optional = true }
# Sync database drivers for standard tooling around setup/teardown/migrations. # Sync database drivers for standard tooling around setup/teardown/migrations.
psycopg2-binary = { version = "^2.9.1", optional = true } psycopg2-binary = { version = "^2.9.1", optional = true }
mysqlclient = { version = "^2.1.0", optional = true } mysqlclient = { version = "^2.1.0", optional = true }
@ -89,23 +89,23 @@ flake8-expression-complexity = "^0.0.11"
# types # types
mypy = "^0.961" mypy = "^0.961"
types-ujson = "^5.3.0" types-ujson = "^5.4.0"
types-PyMySQL = "^1.0.19" types-PyMySQL = "^1.0.19"
types-ipaddress = "^1.0.1" types-ipaddress = "^1.0.1"
types-enum34 = "^1.1.1" types-enum34 = "^1.1.1"
types-cryptography = "^3.3.21" types-cryptography = "^3.3.21"
types-orjson = "^3.6.1" types-orjson = "^3.6.1"
types-aiofiles = "^0.8.8" types-aiofiles = "^0.8.9"
types-pkg-resources = "^0.1.3" types-pkg-resources = "^0.1.3"
types-requests = "^2.27.31" types-requests = "^2.28.2"
types-toml = "^0.10.7" types-toml = "^0.10.8"
# Documantation # Documantation
mkdocs = "^1.2.3" mkdocs = "^1.2.3"
mkdocs-material = ">=8.1.2,<8.4" mkdocs-material = ">=8.1.2,<8.4"
mkdocs-material-extensions = "^1.0.3" mkdocs-material-extensions = "^1.0.3"
mkdocstrings = {version = "==0.19.0", extras = ["python"]} mkdocstrings = {version = "==0.19.0", extras = ["python"]}
mkdocs-gen-files = "^0.3.4" mkdocs-gen-files = "^0.3.5"
mkdocs-literate-nav = "^0.4.1" mkdocs-literate-nav = "^0.4.1"
mkdocs-section-index = "^0.3.4" mkdocs-section-index = "^0.3.4"
dataclasses = { version = ">=0.6.0,<0.8 || >0.8,<1.0.0" } dataclasses = { version = ">=0.6.0,<0.8 || >0.8,<1.0.0" }
@ -113,7 +113,7 @@ dataclasses = { version = ">=0.6.0,<0.8 || >0.8,<1.0.0" }
# Performance testing # Performance testing
yappi = "^1.3.5" yappi = "^1.3.5"
pre-commit = "^2.19.0" pre-commit = "^2.20.0"
[tool.poetry.extras] [tool.poetry.extras]
postgresql = ["asyncpg", "psycopg2-binary"] postgresql = ["asyncpg", "psycopg2-binary"]

View File

@ -1,6 +1,7 @@
# type: ignore # type: ignore
import datetime import datetime
from typing import List, Optional from typing import List, Optional
from collections import Counter
import databases import databases
import pytest import pytest
@ -11,6 +12,7 @@ import ormar
import ormar.fields.constraints import ormar.fields.constraints
from ormar import ModelDefinitionError, property_field from ormar import ModelDefinitionError, property_field
from ormar.exceptions import ModelError from ormar.exceptions import ModelError
from ormar.models.metaclass import get_constraint_copy
from tests.settings import DATABASE_URL from tests.settings import DATABASE_URL
metadata = sa.MetaData() metadata = sa.MetaData()
@ -47,7 +49,13 @@ class DateFieldsModel(ormar.Model):
metadata = metadata metadata = metadata
database = db database = db
constraints = [ constraints = [
ormar.fields.constraints.UniqueColumns("creation_date", "modification_date") ormar.fields.constraints.UniqueColumns(
"creation_date",
"modification_date",
),
ormar.fields.constraints.CheckColumns(
"creation_date <= modification_date",
),
] ]
created_date: datetime.datetime = ormar.DateTime( created_date: datetime.datetime = ormar.DateTime(
@ -234,9 +242,13 @@ def test_model_subclassing_non_abstract_raises_error():
def test_params_are_inherited(): def test_params_are_inherited():
assert Category.Meta.metadata == metadata assert Category.Meta.metadata == metadata
assert Category.Meta.database == db assert Category.Meta.database == db
assert len(Category.Meta.constraints) == 2
assert len(Category.Meta.property_fields) == 2 assert len(Category.Meta.property_fields) == 2
constraints = Counter(map(lambda c: type(c), Category.Meta.constraints))
assert constraints[ormar.fields.constraints.UniqueColumns] == 2
assert constraints[ormar.fields.constraints.IndexColumns] == 0
assert constraints[ormar.fields.constraints.CheckColumns] == 1
def round_date_to_seconds( def round_date_to_seconds(
date: datetime.datetime, date: datetime.datetime,
@ -519,3 +531,8 @@ def test_custom_config():
sam = ImmutablePerson(name="Sam") sam = ImmutablePerson(name="Sam")
with pytest.raises(TypeError): with pytest.raises(TypeError):
sam.name = "Not Sam" sam.name = "Not Sam"
def test_get_constraint_copy():
with pytest.raises(ValueError):
get_constraint_copy("INVALID CONSTRAINT")

View File

@ -0,0 +1,57 @@
import sqlite3
import asyncpg # type: ignore
import databases
import pytest
import sqlalchemy
import ormar.fields.constraints
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Product(ormar.Model):
class Meta:
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)
company: str = ormar.String(max_length=200)
inventory: int = ormar.Integer()
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)
@pytest.mark.asyncio
async def test_check_columns_exclude_mysql():
if Product.Meta.database._backend._dialect.name != "mysql":
async with database: # pragma: no cover
async with database.transaction(force_rollback=True):
await Product.objects.create(
name="Mars", company="Nestle", inventory=100, buffer=10
)
with pytest.raises(
(
sqlite3.IntegrityError,
asyncpg.exceptions.CheckViolationError,
)
):
await Product.objects.create(
name="Cookies", company="Nestle", inventory=1, buffer=10
)