WIP - Pydantic v2 support (#1238)
* WIP * WIP - make test_model_definition tests pass * WIP - make test_model_methods pass * WIP - make whole test suit at least run - failing 49/443 tests * WIP fix part of the getting pydantic tests as types of fields are now kept in core schema and not on fieldsinfo * WIP fix validation in update by creating individual fields validators, failing 36/443 * WIP fix __pydantic_extra__ in intializing model, fix test related to pydantic config checks, failing 32/442 * WIP - fix enum schema in model_json_schema, failing 31/442 * WIP - fix copying through model, fix setting pydantic fields on through, fix default config and inheriting from it, failing 26/442 * WIP fix tests checking pydantic schema, fix excluding parent fields, failing 21/442 * WIP some missed files * WIP - fix validators inheritance and fix validators in generated pydantic, failing 17/442 * WIP - fix through models setting - only on reverse side of relation, but always on reverse side, failing 15/442 * WIP - fix through models setting - only on reverse side of relation, but always on reverse side, failing 15/442 * WIP - working on proper populating __dict__ for relations for new schema dumping, some work on openapi docs, failing 13/442 * WIP - remove property fields as pydantic has now computed_field on its own, failing 9/442 * WIP - fixes in docs, failing 8/442 * 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 * WIP - fix to pk only models in schemas * 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 * solve circular refs * all tests pass 🎉 * remove 3.7 from tests * add lint and type check jobs * reforat with ruff, fix jobs * rename jobs * fix imports * fix evaluate in py3.8 * partially fix coverage * fix coverage, add more tests * fix test ids * fix test ids * fix lint, fix docs, make docs fully working scripts, add test docs job * fix pyproject * pin py ver in test docs * change dir in test docs * fix pydantic warning hack * rm poetry call in test_docs * switch to pathlib in test docs * remove coverage req test docs * fix type check tests, fix part of types * fix/skip next part of types * fix next part of types * fix next part of types * fix coverage * fix coverage * fix type (bit dirty 🤷) * fix some code smells * change pre-commit * tweak workflows * remove no root from tests * switch to full python path by passing sys.executable * some small refactor in new base model, one sample test, change makefile * small refactors to reduce complexity of methods * temp add tests for prs against pydantic_v2 * remove all references to __fields__ * remove all references to construct, deprecate the method and update model_construct to be in line with pydantic * deprecate dict and add model_dump, todo switch to model_dict in calls * fix tests * change to union * change to union * change to model_dump and model_dump_json from dict and json deprecated methods, deprecate them in ormar too * finish switching dict() -> model_dump() * finish switching json() -> model_dump_json() * remove fully pydantic_only * switch to extra for payment card, change missed json calls * fix coverage - no more warnings internal * fix coverage - no more warnings internal - part 2 * split model_construct into own and pydantic parts * split determine pydantic field type * change to new field validators * fix benchmarks, add codspeed instead of pytest-benchmark, add action and gh workflow * restore pytest-benchmark * remove codspeed * pin pydantic version, restore codspeed * change on push to pydantic_v2 to trigger first one * Use lifespan function instead of event (#1259) * check return types * fix imports order, set warnings=False on json that passes the dict, fix unnecessary loop in one of the test * remove references to model's meta as it's now ormar config, rename related methods too * filter out pydantic serializer warnings * remove choices leftovers * remove leftovers after property_fields, keep only enough to exclude them in initialization * add migration guide * fix meta references * downgrade databases for now * Change line numbers in documentation (#1265) * proofread and fix the docs, part 1 * proofread and fix the docs for models * proofread and fix the docs for fields * proofread and fix the docs for relations * proofread and fix rest of the docs, add release notes for 0.20 * create tables in new docs src * cleanup old deps, uncomment docs publish on tag * fix import reorder --------- Co-authored-by: TouwaStar <30479449+TouwaStar@users.noreply.github.com> Co-authored-by: Goran Mekić <meka@tilda.center>
This commit is contained in:
@ -1,114 +1,93 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import databases
|
||||
import ormar as orm
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar as orm
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class MainMeta(orm.ModelMeta):
|
||||
database = database
|
||||
metadata = metadata
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
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 +96,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 +117,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 +131,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 +139,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 +152,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):
|
||||
@ -192,8 +166,7 @@ class Changelog(orm.Model):
|
||||
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 +183,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,8 +206,7 @@ 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):
|
||||
@ -259,8 +230,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):
|
||||
@ -291,8 +261,7 @@ class Tag(orm.Model):
|
||||
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,8 +274,7 @@ 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):
|
||||
@ -328,18 +296,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"},
|
||||
@ -349,19 +311,25 @@ async def test_very_complex_relation_map():
|
||||
{
|
||||
"id": 9,
|
||||
"title": "prueba-2321",
|
||||
"description": "\n<!--- start changelog ver.v.1.3.0.0 -->\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<!--- end changelog ver.v.1.3.0.0 -->\n",
|
||||
"description": "\n<!--- start changelog ver.v.1.3.0.0 -->"
|
||||
"Description 1"
|
||||
"<!--- end changelog ver.v.1.3.0.0 -->\n",
|
||||
"data": {},
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"title": "prueba-123-prod",
|
||||
"description": "\n<!--- start changelog ver.v.1.2.0.0 -->\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<!--- end changelog ver.v.1.2.0.0 -->\n",
|
||||
"description": "\n<!--- start changelog ver.v.1.3.0.0 -->"
|
||||
"Description 2"
|
||||
"<!--- end changelog ver.v.1.3.0.0 -->\n",
|
||||
"data": {},
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"title": "prueba-3-2",
|
||||
"description": "\n<!--- start changelog ver.v.1.1.0.0 -->\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<!--- end changelog ver.v.1.1.0.0 -->\n",
|
||||
"description": "\n<!--- start changelog ver.v.1.3.0.0 -->"
|
||||
"Description 3"
|
||||
"<!--- end changelog ver.v.1.3.0.0 -->\n",
|
||||
"data": {},
|
||||
},
|
||||
]
|
||||
@ -373,45 +341,42 @@ 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 = [
|
||||
{
|
||||
"id": 9,
|
||||
"title": "prueba-2321",
|
||||
"description": "\n<!--- start changelog ver.v.1.3.0.0 -->\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<!--- end changelog ver.v.1.3.0.0 -->\n",
|
||||
"description": "\n<!--- start changelog ver.v.1.3.0.0 -->"
|
||||
"Description 1"
|
||||
"<!--- end changelog ver.v.1.3.0.0 -->\n",
|
||||
"data": {},
|
||||
"tag": {
|
||||
"id": 18,
|
||||
"taglabel": None,
|
||||
"tagcommit": None,
|
||||
"tagissue": None,
|
||||
},
|
||||
"changelogs": [],
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"title": "prueba-123-prod",
|
||||
"description": "\n<!--- start changelog ver.v.1.2.0.0 -->\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<!--- end changelog ver.v.1.2.0.0 -->\n",
|
||||
"description": "\n<!--- start changelog ver.v.1.3.0.0 -->"
|
||||
"Description 2"
|
||||
"<!--- end changelog ver.v.1.3.0.0 -->\n",
|
||||
"data": {},
|
||||
"tag": {
|
||||
"id": 17,
|
||||
"taglabel": None,
|
||||
"tagcommit": None,
|
||||
"tagissue": None,
|
||||
},
|
||||
"changelogs": [],
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"title": "prueba-3-2",
|
||||
"description": "\n<!--- start changelog ver.v.1.1.0.0 -->\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<!--- end changelog ver.v.1.1.0.0 -->\n",
|
||||
"description": "\n<!--- start changelog ver.v.1.3.0.0 -->"
|
||||
"Description 3"
|
||||
"<!--- end changelog ver.v.1.3.0.0 -->\n",
|
||||
"data": {},
|
||||
"tag": {
|
||||
"id": 12,
|
||||
"taglabel": None,
|
||||
"tagcommit": None,
|
||||
"tagissue": None,
|
||||
},
|
||||
"changelogs": [],
|
||||
},
|
||||
|
||||
@ -1,32 +1,23 @@
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class MainMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
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 +27,14 @@ class User(ormar.Model):
|
||||
|
||||
|
||||
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 +42,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)
|
||||
@ -68,6 +50,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)
|
||||
@ -90,13 +75,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"
|
||||
@ -104,17 +89,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"
|
||||
@ -122,7 +107,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"]
|
||||
@ -131,7 +116,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"
|
||||
@ -141,7 +126,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"
|
||||
@ -150,7 +135,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"}}},
|
||||
)
|
||||
@ -164,25 +149,31 @@ 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": {
|
||||
"email": "test@test.com",
|
||||
"first_name": "Anna",
|
||||
"password": "ijacids7^*&",
|
||||
"roles": [{"name": "User"}, {"name": "Admin"}],
|
||||
"roles": [
|
||||
{"name": "User"},
|
||||
{"name": "Admin"},
|
||||
],
|
||||
},
|
||||
"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": {
|
||||
"email": "test@test.com",
|
||||
"first_name": "Anna",
|
||||
"password": "ijacids7^*&",
|
||||
"roles": [{"name": "User"}, {"name": "Admin"}],
|
||||
"roles": [
|
||||
{"name": "User"},
|
||||
{"name": "Admin"},
|
||||
],
|
||||
},
|
||||
"name": "Teddy Bear",
|
||||
}
|
||||
|
||||
@ -1,24 +1,16 @@
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar.models.excludable import ExcludableItems
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
database = database
|
||||
metadata = metadata
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
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")
|
||||
@ -26,13 +18,11 @@ class NickNames(ormar.Model):
|
||||
|
||||
|
||||
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")
|
||||
@ -40,8 +30,7 @@ class HQ(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")
|
||||
@ -50,8 +39,7 @@ class Company(ormar.Model):
|
||||
|
||||
|
||||
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)
|
||||
@ -62,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"}
|
||||
@ -69,7 +60,9 @@ 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()
|
||||
@ -78,7 +71,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()
|
||||
@ -204,7 +197,9 @@ 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"}
|
||||
|
||||
@ -1,44 +1,28 @@
|
||||
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 ConfigDict, computed_field
|
||||
|
||||
import ormar
|
||||
from ormar import post_save, property_field
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
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
|
||||
# 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
|
||||
@ -51,8 +35,7 @@ class UserCreateSchema(UserBase):
|
||||
|
||||
|
||||
class UserSchema(UserBase):
|
||||
class Config:
|
||||
orm_mode = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
def gen_pass():
|
||||
@ -61,10 +44,7 @@ def gen_pass():
|
||||
|
||||
|
||||
class RandomModel(ormar.Model):
|
||||
class Meta:
|
||||
tablename: str = "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)
|
||||
@ -74,16 +54,13 @@ class RandomModel(ormar.Model):
|
||||
server_default=sqlalchemy.func.now()
|
||||
)
|
||||
|
||||
@property_field
|
||||
@computed_field
|
||||
def full_name(self) -> str:
|
||||
return " ".join([self.first_name, self.last_name])
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta:
|
||||
tablename: str = "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)
|
||||
@ -94,10 +71,7 @@ class User(ormar.Model):
|
||||
|
||||
|
||||
class User2(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)
|
||||
@ -105,17 +79,10 @@ 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")
|
||||
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"})
|
||||
@ -126,7 +93,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)
|
||||
@ -136,7 +103,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)
|
||||
@ -276,12 +243,11 @@ async def test_adding_fields_in_endpoints2():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_excluding_property_field_in_endpoints2():
|
||||
|
||||
dummy_registry = {}
|
||||
|
||||
@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):
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
import random
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
def get_position() -> int:
|
||||
@ -17,10 +15,7 @@ def get_position() -> int:
|
||||
|
||||
|
||||
class Album(ormar.Model):
|
||||
class Meta:
|
||||
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)
|
||||
@ -28,10 +23,7 @@ class Album(ormar.Model):
|
||||
|
||||
|
||||
class Track(ormar.Model):
|
||||
class Meta:
|
||||
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,19 +32,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)
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
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()
|
||||
|
||||
|
||||
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, nullable=False)
|
||||
@ -24,10 +19,7 @@ class Company(ormar.Model):
|
||||
|
||||
|
||||
class Car(ormar.Model):
|
||||
class Meta:
|
||||
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)
|
||||
@ -38,19 +30,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,
|
||||
@ -173,8 +159,62 @@ 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"]
|
||||
).all()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_excluding_nested_lists_in_dump():
|
||||
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,
|
||||
name="Corolla",
|
||||
year=2020,
|
||||
gearbox_type="Manual",
|
||||
gears=5,
|
||||
aircon_type="Manual",
|
||||
)
|
||||
car2 = 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.model_dump() == {
|
||||
"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.model_dump(exclude_list=True) == {
|
||||
"founded": 1937,
|
||||
"id": toyota.id,
|
||||
"name": "Toyota",
|
||||
}
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
from typing import List
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
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)
|
||||
@ -23,10 +18,7 @@ class Category(ormar.Model):
|
||||
|
||||
|
||||
class Item(ormar.Model):
|
||||
class Meta:
|
||||
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)
|
||||
@ -34,49 +26,44 @@ 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.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",
|
||||
"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:
|
||||
async with base_ormar_config.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,
|
||||
@ -84,34 +71,34 @@ 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,
|
||||
}
|
||||
assert (
|
||||
category2.json(exclude_none=True)
|
||||
== '{"id": 2, "visibility": true, "items": []}'
|
||||
category2.model_dump_json(exclude_none=True)
|
||||
== '{"id":2,"visibility":true,"items":[]}'
|
||||
)
|
||||
|
||||
|
||||
@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.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",
|
||||
@ -119,7 +106,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",
|
||||
@ -127,7 +114,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",
|
||||
|
||||
Reference in New Issue
Block a user