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:
33
tests/lifespan.py
Normal file
33
tests/lifespan.py
Normal file
@ -0,0 +1,33 @@
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator
|
||||
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from fastapi import FastAPI
|
||||
|
||||
|
||||
def lifespan(config):
|
||||
@asynccontextmanager
|
||||
async def do_lifespan(_: FastAPI) -> AsyncIterator[None]:
|
||||
if not config.database.is_connected:
|
||||
await config.database.connect()
|
||||
|
||||
yield
|
||||
|
||||
if config.database.is_connected:
|
||||
await config.database.disconnect()
|
||||
|
||||
return do_lifespan
|
||||
|
||||
|
||||
def init_tests(config, scope="module"):
|
||||
@pytest.fixture(autouse=True, scope=scope)
|
||||
def create_database():
|
||||
config.engine = sqlalchemy.create_engine(config.database.url._url)
|
||||
config.metadata.create_all(config.engine)
|
||||
|
||||
yield
|
||||
|
||||
config.metadata.drop_all(config.engine)
|
||||
|
||||
return create_database
|
||||
@ -1,9 +1,23 @@
|
||||
import os
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import sqlalchemy
|
||||
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///test.db")
|
||||
database_url = databases.DatabaseURL(DATABASE_URL)
|
||||
if database_url.scheme == "postgresql+aiopg": # pragma no cover
|
||||
DATABASE_URL = str(database_url.replace(driver=None))
|
||||
print("USED DB:", DATABASE_URL)
|
||||
|
||||
|
||||
def create_config(**args):
|
||||
database_ = databases.Database(DATABASE_URL, **args)
|
||||
metadata_ = sqlalchemy.MetaData()
|
||||
engine_ = sqlalchemy.create_engine(DATABASE_URL)
|
||||
|
||||
return ormar.OrmarConfig(
|
||||
metadata=metadata_,
|
||||
database=database_,
|
||||
engine=engine_,
|
||||
)
|
||||
|
||||
@ -1,31 +1,20 @@
|
||||
# type: ignore
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy as sa
|
||||
from pydantic.typing import ForwardRef
|
||||
from sqlalchemy import create_engine
|
||||
from typing import ForwardRef, List, Optional
|
||||
|
||||
import ormar
|
||||
from ormar import ModelMeta
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
metadata = sa.MetaData()
|
||||
db = databases.Database(DATABASE_URL)
|
||||
engine = create_engine(DATABASE_URL)
|
||||
|
||||
TeacherRef = ForwardRef("Teacher")
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
|
||||
|
||||
class Student(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -35,14 +24,11 @@ class Student(ormar.Model):
|
||||
|
||||
|
||||
class StudentTeacher(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "students_x_teachers"
|
||||
ormar_config = base_ormar_config.copy(tablename="students_x_teachers")
|
||||
|
||||
|
||||
class Teacher(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -58,8 +44,7 @@ CountryRef = ForwardRef("Country")
|
||||
|
||||
|
||||
class Country(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "countries"
|
||||
ormar_config = base_ormar_config.copy(tablename="countries")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=128)
|
||||
@ -70,8 +55,7 @@ class Country(ormar.Model):
|
||||
|
||||
|
||||
class City(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "cities"
|
||||
ormar_config = base_ormar_config.copy(tablename="cities")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=128)
|
||||
@ -83,17 +67,13 @@ class City(ormar.Model):
|
||||
Country.update_forward_refs()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_double_relations():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
t1 = await Teacher.objects.create(name="Mr. Jones")
|
||||
t2 = await Teacher.objects.create(name="Ms. Smith")
|
||||
t3 = await Teacher.objects.create(name="Mr. Quibble")
|
||||
@ -150,8 +130,8 @@ async def test_double_relations():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auto_through_model():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
england = await Country(name="England").save()
|
||||
france = await Country(name="France").save()
|
||||
london = await City(name="London", country=england).save()
|
||||
|
||||
@ -1,29 +1,23 @@
|
||||
# type: ignore
|
||||
from typing import List
|
||||
from typing import ForwardRef, List, Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import sqlalchemy as sa
|
||||
from pydantic.typing import ForwardRef
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
from ormar import ModelMeta
|
||||
from ormar.exceptions import ModelError
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
metadata = sa.MetaData()
|
||||
db = databases.Database(DATABASE_URL)
|
||||
engine = create_engine(DATABASE_URL)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
PersonRef = ForwardRef("Person")
|
||||
|
||||
|
||||
class Person(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -38,9 +32,7 @@ ChildFriendRef = ForwardRef("ChildFriend")
|
||||
|
||||
|
||||
class Child(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -54,15 +46,11 @@ class Child(ormar.Model):
|
||||
|
||||
|
||||
class ChildFriend(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
|
||||
class Game(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -71,17 +59,13 @@ class Game(ormar.Model):
|
||||
Child.update_forward_refs()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(scope="function")
|
||||
async def cleanup():
|
||||
yield
|
||||
async with db:
|
||||
async with base_ormar_config.database:
|
||||
await ChildFriend.objects.delete(each=True)
|
||||
await Child.objects.delete(each=True)
|
||||
await Game.objects.delete(each=True)
|
||||
@ -93,9 +77,7 @@ async def test_not_updated_model_raises_errors():
|
||||
Person2Ref = ForwardRef("Person2")
|
||||
|
||||
class Person2(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -116,14 +98,10 @@ async def test_not_updated_model_m2m_raises_errors():
|
||||
Person3Ref = ForwardRef("Person3")
|
||||
|
||||
class PersonFriend(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
class Person3(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -146,17 +124,13 @@ async def test_not_updated_model_m2m_through_raises_errors():
|
||||
PersonPetRef = ForwardRef("PersonPet")
|
||||
|
||||
class Pet(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
class Person4(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -165,9 +139,7 @@ async def test_not_updated_model_m2m_through_raises_errors():
|
||||
)
|
||||
|
||||
class PersonPet(ormar.Model):
|
||||
class Meta(ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
with pytest.raises(ModelError):
|
||||
await Person4.objects.create(name="Test")
|
||||
@ -180,25 +152,25 @@ async def test_not_updated_model_m2m_through_raises_errors():
|
||||
|
||||
|
||||
def test_proper_field_init():
|
||||
assert "supervisor" in Person.Meta.model_fields
|
||||
assert Person.Meta.model_fields["supervisor"].to == Person
|
||||
assert "supervisor" in Person.ormar_config.model_fields
|
||||
assert Person.ormar_config.model_fields["supervisor"].to == Person
|
||||
|
||||
assert "supervisor" in Person.__fields__
|
||||
assert Person.__fields__["supervisor"].type_ == Person
|
||||
assert "supervisor" in Person.model_fields
|
||||
assert Person.model_fields["supervisor"].annotation == Optional[Person]
|
||||
|
||||
assert "supervisor" in Person.Meta.table.columns
|
||||
assert "supervisor" in Person.ormar_config.table.columns
|
||||
assert isinstance(
|
||||
Person.Meta.table.columns["supervisor"].type, sa.sql.sqltypes.Integer
|
||||
Person.ormar_config.table.columns["supervisor"].type, sa.sql.sqltypes.Integer
|
||||
)
|
||||
assert len(Person.Meta.table.columns["supervisor"].foreign_keys) > 0
|
||||
assert len(Person.ormar_config.table.columns["supervisor"].foreign_keys) > 0
|
||||
|
||||
assert "person_supervisor" in Person.Meta.alias_manager._aliases_new
|
||||
assert "person_supervisor" in Person.ormar_config.alias_manager._aliases_new
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_self_relation():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
sam = await Person.objects.create(name="Sam")
|
||||
joe = await Person(name="Joe", supervisor=sam).save()
|
||||
assert joe.supervisor.name == "Sam"
|
||||
@ -215,8 +187,8 @@ async def test_self_relation():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_other_forwardref_relation(cleanup):
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
checkers = await Game.objects.create(name="checkers")
|
||||
uno = await Game(name="Uno").save()
|
||||
|
||||
@ -242,8 +214,8 @@ async def test_other_forwardref_relation(cleanup):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_m2m_self_forwardref_relation(cleanup):
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
checkers = await Game.objects.create(name="Checkers")
|
||||
uno = await Game(name="Uno").save()
|
||||
jenga = await Game(name="Jenga").save()
|
||||
|
||||
@ -1,42 +1,30 @@
|
||||
import asyncio
|
||||
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(force_rollback=True)
|
||||
|
||||
|
||||
class Department(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "departments"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="departments")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True, autoincrement=False)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class SchoolClass(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "schoolclasses"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="schoolclasses")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
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)
|
||||
@ -44,10 +32,7 @@ class Category(ormar.Model):
|
||||
|
||||
|
||||
class Student(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "students"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="students")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -56,10 +41,7 @@ class Student(ormar.Model):
|
||||
|
||||
|
||||
class Teacher(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "teachers"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="teachers")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -67,13 +49,7 @@ class Teacher(ormar.Model):
|
||||
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
async def create_data():
|
||||
@ -91,35 +67,35 @@ async def create_data():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_multiple_instances_of_same_table_in_schema():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await create_data()
|
||||
classes = await SchoolClass.objects.select_related(
|
||||
["teachers__category__department", "students__category__department"]
|
||||
).all()
|
||||
assert classes[0].name == "Math"
|
||||
assert classes[0].students[0].name == "Jane"
|
||||
assert len(classes[0].dict().get("students")) == 2
|
||||
assert len(classes[0].model_dump().get("students")) == 2
|
||||
assert classes[0].teachers[0].category.department.name == "Law Department"
|
||||
assert classes[0].students[0].category.department.name == "Math Department"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_all_multiple_instances_of_same_table_in_schema():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await create_data()
|
||||
math_class = await SchoolClass.objects.get(name="Math")
|
||||
assert math_class.name == "Math"
|
||||
|
||||
await math_class.load_all(follow=True)
|
||||
assert math_class.students[0].name == "Jane"
|
||||
assert len(math_class.dict().get("students")) == 2
|
||||
assert len(math_class.model_dump().get("students")) == 2
|
||||
assert math_class.teachers[0].category.department.name == "Law Department"
|
||||
assert math_class.students[0].category.department.name == "Math Department"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_filter_groups_with_instances_of_same_table_in_schema():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await create_data()
|
||||
math_class = (
|
||||
await SchoolClass.objects.select_related(
|
||||
@ -136,7 +112,7 @@ async def test_filter_groups_with_instances_of_same_table_in_schema():
|
||||
)
|
||||
assert math_class.name == "Math"
|
||||
assert math_class.students[0].name == "Jane"
|
||||
assert len(math_class.dict().get("students")) == 2
|
||||
assert len(math_class.model_dump().get("students")) == 2
|
||||
assert math_class.teachers[0].category.department.name == "Law Department"
|
||||
assert math_class.students[0].category.department.name == "Math Department"
|
||||
|
||||
|
||||
@ -1,32 +1,23 @@
|
||||
import asyncio
|
||||
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()
|
||||
|
||||
|
||||
class Department(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "departments"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="departments")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True, autoincrement=False)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class SchoolClass(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "schoolclasses"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="schoolclasses")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -34,20 +25,14 @@ class SchoolClass(ormar.Model):
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "categories"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Student(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "students"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="students")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -56,10 +41,7 @@ class Student(ormar.Model):
|
||||
|
||||
|
||||
class Teacher(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "teachers"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="teachers")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -67,13 +49,7 @@ class Teacher(ormar.Model):
|
||||
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
async def create_data():
|
||||
@ -91,8 +67,8 @@ async def create_data():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_multiple_instances_of_same_table_in_schema():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await create_data()
|
||||
classes = await SchoolClass.objects.select_related(
|
||||
["teachers__category", "students__schoolclass"]
|
||||
@ -100,9 +76,10 @@ async def test_model_multiple_instances_of_same_table_in_schema():
|
||||
assert classes[0].name == "Math"
|
||||
assert classes[0].students[0].name == "Jane"
|
||||
|
||||
assert len(classes[0].dict().get("students")) == 2
|
||||
assert len(classes[0].model_dump().get("students")) == 2
|
||||
|
||||
# since it's going from schoolclass => teacher => schoolclass (same class) department is already populated
|
||||
# since it's going from schoolclass => teacher
|
||||
# => schoolclass (same class) department is already populated
|
||||
assert classes[0].students[0].schoolclass.name == "Math"
|
||||
assert classes[0].students[0].schoolclass.department.name is None
|
||||
await classes[0].students[0].schoolclass.department.load()
|
||||
@ -118,8 +95,8 @@ async def test_model_multiple_instances_of_same_table_in_schema():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_right_tables_join():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await create_data()
|
||||
classes = await SchoolClass.objects.select_related(
|
||||
["teachers__category", "students"]
|
||||
@ -133,8 +110,8 @@ async def test_right_tables_join():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_multiple_reverse_related_objects():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await create_data()
|
||||
classes = await SchoolClass.objects.select_related(
|
||||
["teachers__category", "students__category"]
|
||||
|
||||
@ -1,29 +1,20 @@
|
||||
# type: ignore
|
||||
import base64
|
||||
import datetime
|
||||
import decimal
|
||||
import hashlib
|
||||
import uuid
|
||||
import datetime
|
||||
from typing import Any
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
from ormar import ModelDefinitionError, NoMatch
|
||||
from ormar.fields.sqlalchemy_encrypted import EncryptedString
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
default_fernet = dict(
|
||||
encrypt_secret="asd123", encrypt_backend=ormar.EncryptBackends.FERNET
|
||||
)
|
||||
@ -41,8 +32,7 @@ class DummyBackend(ormar.fields.EncryptBackend):
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, **default_fernet)
|
||||
@ -70,6 +60,10 @@ class Author(ormar.Model):
|
||||
test_smallint: int = ormar.SmallInteger(default=0, **default_fernet)
|
||||
test_decimal = ormar.Decimal(scale=2, precision=10, **default_fernet)
|
||||
test_decimal2 = ormar.Decimal(max_digits=10, decimal_places=2, **default_fernet)
|
||||
test_bytes = ormar.LargeBinary(max_length=100, **default_fernet)
|
||||
test_b64bytes = ormar.LargeBinary(
|
||||
max_length=100, represent_as_base64_str=True, **default_fernet
|
||||
)
|
||||
custom_backend: str = ormar.String(
|
||||
max_length=200,
|
||||
encrypt_secret="asda8",
|
||||
@ -79,8 +73,7 @@ class Author(ormar.Model):
|
||||
|
||||
|
||||
class Hash(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "hashes"
|
||||
ormar_config = base_ormar_config.copy(tablename="hashes")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(
|
||||
@ -91,8 +84,7 @@ class Hash(ormar.Model):
|
||||
|
||||
|
||||
class Filter(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "filters"
|
||||
ormar_config = base_ormar_config.copy(tablename="filters")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, **default_fernet)
|
||||
@ -100,29 +92,21 @@ class Filter(ormar.Model):
|
||||
|
||||
|
||||
class Report(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "reports"
|
||||
ormar_config = base_ormar_config.copy(tablename="reports")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
filters = ormar.ManyToMany(Filter)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_error_on_encrypted_pk():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class Wrong(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "wrongs"
|
||||
ormar_config = base_ormar_config.copy(tablename="wrongs")
|
||||
|
||||
id: int = ormar.Integer(
|
||||
primary_key=True,
|
||||
@ -135,8 +119,7 @@ def test_error_on_encrypted_relation():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class Wrong2(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "wrongs2"
|
||||
ormar_config = base_ormar_config.copy(tablename="wrongs2")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author = ormar.ForeignKey(
|
||||
@ -150,8 +133,7 @@ def test_error_on_encrypted_m2m_relation():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class Wrong3(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "wrongs3"
|
||||
ormar_config = base_ormar_config.copy(tablename="wrongs3")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author = ormar.ManyToMany(
|
||||
@ -165,8 +147,7 @@ def test_wrong_backend():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class Wrong3(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "wrongs3"
|
||||
ormar_config = base_ormar_config.copy(tablename="wrongs3")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author = ormar.Integer(
|
||||
@ -177,12 +158,12 @@ def test_wrong_backend():
|
||||
|
||||
|
||||
def test_db_structure():
|
||||
assert Author.Meta.table.c.get("name").type.__class__ == EncryptedString
|
||||
assert Author.ormar_config.table.c.get("name").type.__class__ == EncryptedString
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_save_and_retrieve():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
test_uuid = uuid.uuid4()
|
||||
await Author(
|
||||
name="Test",
|
||||
@ -191,10 +172,12 @@ async def test_save_and_retrieve():
|
||||
uuid_test=test_uuid,
|
||||
test_float=1.2,
|
||||
test_bool=True,
|
||||
test_decimal=decimal.Decimal(3.5),
|
||||
test_decimal=3.57,
|
||||
test_decimal2=decimal.Decimal(5.5),
|
||||
test_json=dict(aa=12),
|
||||
custom_backend="test12",
|
||||
test_bytes=b"test",
|
||||
test_b64bytes=b"test2",
|
||||
).save()
|
||||
author = await Author.objects.get()
|
||||
|
||||
@ -214,14 +197,17 @@ async def test_save_and_retrieve():
|
||||
assert author.test_float2 is None
|
||||
assert author.test_bigint == 0
|
||||
assert author.test_json == {"aa": 12}
|
||||
assert author.test_decimal == 3.5
|
||||
assert float(author.test_decimal) == 3.57
|
||||
assert author.test_decimal2 == 5.5
|
||||
assert author.custom_backend == "test12"
|
||||
assert author.test_bytes == "test".encode("utf-8")
|
||||
assert author.test_b64bytes == "dGVzdDI="
|
||||
assert base64.b64decode(author.test_b64bytes) == b"test2"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fernet_filters_nomatch():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Filter(name="test1").save()
|
||||
await Filter(name="test1").save()
|
||||
|
||||
@ -236,7 +222,7 @@ async def test_fernet_filters_nomatch():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hash_filters_works():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Hash(name="test1").save()
|
||||
await Hash(name="test2").save()
|
||||
|
||||
@ -253,7 +239,7 @@ async def test_hash_filters_works():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_related_model_fields_properly_decrypted():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
hash1 = await Hash(name="test1").save()
|
||||
report = await Report.objects.create(name="Report1")
|
||||
await report.filters.create(name="test1", hash=hash1)
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -1,63 +1,44 @@
|
||||
import base64
|
||||
import json
|
||||
import uuid
|
||||
from enum import Enum
|
||||
from typing import List
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
app.state.database = database
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
headers = {"content-type": "application/json"}
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
blob3 = b"\xc3\x28"
|
||||
blob3 = b"\xc3\x83\x28"
|
||||
blob4 = b"\xf0\x28\x8c\x28"
|
||||
blob5 = b"\xee"
|
||||
blob6 = b"\xff"
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
class BinaryEnum(Enum):
|
||||
blob3 = blob3
|
||||
blob4 = blob4
|
||||
blob5 = blob5
|
||||
blob6 = blob6
|
||||
|
||||
|
||||
class BinaryThing(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "things"
|
||||
ormar_config = base_ormar_config.copy(tablename="things")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
bt: str = ormar.LargeBinary(
|
||||
max_length=1000,
|
||||
choices=[blob3, blob4, blob5, blob6],
|
||||
represent_as_base64_str=True,
|
||||
)
|
||||
bt: str = ormar.LargeBinary(represent_as_base64_str=True, max_length=100)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.get("/things", response_model=List[BinaryThing])
|
||||
@ -71,14 +52,6 @@ async def create_things(thing: BinaryThing):
|
||||
return thing
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_main():
|
||||
client = AsyncClient(app=app, base_url="http://testserver")
|
||||
@ -90,17 +63,15 @@ async def test_read_main():
|
||||
)
|
||||
assert response.status_code == 200
|
||||
response = await client.get("/things")
|
||||
assert response.json()[0]["bt"] == base64.b64encode(blob3).decode()
|
||||
thing = BinaryThing(**response.json()[0])
|
||||
assert response.json()[0]["bt"] == blob3.decode()
|
||||
resp_json = response.json()
|
||||
resp_json[0]["bt"] = resp_json[0]["bt"].encode()
|
||||
thing = BinaryThing(**resp_json[0])
|
||||
assert thing.__dict__["bt"] == blob3
|
||||
assert thing.bt == base64.b64encode(blob3).decode()
|
||||
|
||||
|
||||
def test_schema():
|
||||
schema = BinaryThing.schema()
|
||||
schema = BinaryThing.model_json_schema()
|
||||
assert schema["properties"]["bt"]["format"] == "base64"
|
||||
converted_choices = ["7g==", "/w==", "8CiMKA==", "wyg="]
|
||||
assert len(schema["properties"]["bt"]["enum"]) == 4
|
||||
assert all(
|
||||
choice in schema["properties"]["bt"]["enum"] for choice in converted_choices
|
||||
)
|
||||
assert schema["example"]["bt"] == "string"
|
||||
|
||||
@ -1,151 +0,0 @@
|
||||
import datetime
|
||||
import decimal
|
||||
import uuid
|
||||
from enum import Enum
|
||||
|
||||
import databases
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
app = FastAPI()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
app.state.database = database
|
||||
|
||||
uuid1 = uuid.uuid4()
|
||||
uuid2 = uuid.uuid4()
|
||||
|
||||
|
||||
blob = b"test"
|
||||
blob2 = b"test2icac89uc98"
|
||||
|
||||
|
||||
class EnumTest(Enum):
|
||||
val1 = "Val1"
|
||||
val2 = "Val2"
|
||||
|
||||
|
||||
class Organisation(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "org"
|
||||
metadata = metadata
|
||||
database = database
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
ident: str = ormar.String(max_length=100, choices=["ACME Ltd", "Other ltd"])
|
||||
priority: int = ormar.Integer(choices=[1, 2, 3, 4, 5])
|
||||
priority2: int = ormar.BigInteger(choices=[1, 2, 3, 4, 5])
|
||||
priority3: int = ormar.SmallInteger(choices=[1, 2, 3, 4, 5])
|
||||
expire_date: datetime.date = ormar.Date(
|
||||
choices=[datetime.date(2021, 1, 1), datetime.date(2022, 5, 1)]
|
||||
)
|
||||
expire_time: datetime.time = ormar.Time(
|
||||
choices=[datetime.time(10, 0, 0), datetime.time(12, 30)]
|
||||
)
|
||||
|
||||
expire_datetime: datetime.datetime = ormar.DateTime(
|
||||
choices=[
|
||||
datetime.datetime(2021, 1, 1, 10, 0, 0),
|
||||
datetime.datetime(2022, 5, 1, 12, 30),
|
||||
]
|
||||
)
|
||||
random_val: float = ormar.Float(choices=[2.0, 3.5])
|
||||
random_decimal: decimal.Decimal = ormar.Decimal(
|
||||
scale=2, precision=4, choices=[decimal.Decimal(12.4), decimal.Decimal(58.2)]
|
||||
)
|
||||
random_json: pydantic.Json = ormar.JSON(choices=["aa", '{"aa": "bb"}'])
|
||||
random_uuid: uuid.UUID = ormar.UUID(choices=[uuid1, uuid2])
|
||||
enum_string: str = ormar.String(max_length=100, choices=list(EnumTest))
|
||||
blob_col: bytes = ormar.LargeBinary(max_length=100000, choices=[blob, blob2])
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
@app.post("/items/", response_model=Organisation)
|
||||
async def create_item(item: Organisation):
|
||||
await item.save()
|
||||
return item
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_all_endpoints():
|
||||
client = AsyncClient(app=app, base_url="http://testserver")
|
||||
async with client as client, LifespanManager(app):
|
||||
response = await client.post(
|
||||
"/items/",
|
||||
json={"id": 1, "ident": "", "priority": 4, "expire_date": "2022-05-01"},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
response = await client.post(
|
||||
"/items/",
|
||||
json={
|
||||
"id": 1,
|
||||
"ident": "ACME Ltd",
|
||||
"priority": 4,
|
||||
"priority2": 2,
|
||||
"priority3": 1,
|
||||
"expire_date": "2022-05-01",
|
||||
"expire_time": "10:00:00",
|
||||
"expire_datetime": "2022-05-01T12:30:00",
|
||||
"random_val": 3.5,
|
||||
"random_decimal": 12.4,
|
||||
"random_json": '{"aa": "bb"}',
|
||||
"random_uuid": str(uuid1),
|
||||
"enum_string": EnumTest.val1.value,
|
||||
"blob_col": blob.decode("utf-8"),
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
item = Organisation(**response.json())
|
||||
assert item.pk is not None
|
||||
response = await client.get("/docs")
|
||||
assert response.status_code == 200
|
||||
assert b"<title>FastAPI - Swagger UI</title>" in response.content
|
||||
|
||||
|
||||
def test_schema_modification():
|
||||
schema = Organisation.schema()
|
||||
for field in ["ident", "priority", "expire_date"]:
|
||||
assert field in schema["properties"]
|
||||
assert schema["properties"].get(field).get("enum") == list(
|
||||
Organisation.Meta.model_fields.get(field).choices
|
||||
)
|
||||
assert "An enumeration." in schema["properties"].get(field).get("description")
|
||||
|
||||
|
||||
def test_schema_gen():
|
||||
schema = app.openapi()
|
||||
assert "Organisation" in schema["components"]["schemas"]
|
||||
props = schema["components"]["schemas"]["Organisation"]["properties"]
|
||||
for field in [k for k in Organisation.Meta.model_fields.keys() if k != "id"]:
|
||||
assert "enum" in props.get(field)
|
||||
assert "description" in props.get(field)
|
||||
assert "An enumeration." in props.get(field).get("description")
|
||||
@ -1,37 +1,28 @@
|
||||
from typing import Optional
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
app = FastAPI()
|
||||
DATABASE_URL = "sqlite:///db.sqlite"
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
class CA(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "cas"
|
||||
ormar_config = base_ormar_config.copy(tablename="cas")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
ca_name: str = ormar.Text(default="")
|
||||
|
||||
|
||||
class CB1(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "cb1s"
|
||||
ormar_config = base_ormar_config.copy(tablename="cb1s")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
cb1_name: str = ormar.Text(default="")
|
||||
@ -39,14 +30,16 @@ class CB1(ormar.Model):
|
||||
|
||||
|
||||
class CB2(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "cb2s"
|
||||
ormar_config = base_ormar_config.copy(tablename="cb2s")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
cb2_name: str = ormar.Text(default="")
|
||||
ca2: Optional[CA] = ormar.ForeignKey(CA, nullable=True)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.get("/ca", response_model=CA)
|
||||
async def get_ca(): # pragma: no cover
|
||||
return None
|
||||
@ -70,6 +63,7 @@ async def test_all_endpoints():
|
||||
assert response.status_code == 200, response.text
|
||||
schema = response.json()
|
||||
components = schema["components"]["schemas"]
|
||||
assert all(x in components for x in ["CA", "CB1", "CB2"])
|
||||
pk_onlys = [x for x in list(components.keys()) if x.startswith("PkOnly")]
|
||||
assert len(pk_onlys) == 2
|
||||
raw_names_w_o_modules = [x.split("__")[-1] for x in components.keys()]
|
||||
assert all(x in raw_names_w_o_modules for x in ["CA", "CB1", "CB2"])
|
||||
pk_onlys = [x for x in list(raw_names_w_o_modules) if x.startswith("PkOnly")]
|
||||
assert len(pk_onlys) == 4
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
from enum import Enum
|
||||
|
||||
import databases
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
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
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class MyEnum(Enum):
|
||||
@ -16,18 +14,17 @@ class MyEnum(Enum):
|
||||
|
||||
|
||||
class EnumExample(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "enum_example"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="enum_example")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
size: MyEnum = ormar.Enum(enum_class=MyEnum, default=MyEnum.SMALL)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_proper_schema():
|
||||
schema = EnumExample.schema_json()
|
||||
assert (
|
||||
'{"MyEnum": {"title": "MyEnum", "description": "An enumeration.", '
|
||||
'"enum": [1, 2]}}' in schema
|
||||
)
|
||||
schema = EnumExample.model_json_schema()
|
||||
assert {"MyEnum": {"title": "MyEnum", "enum": [1, 2], "type": "integer"}} == schema[
|
||||
"$defs"
|
||||
]
|
||||
|
||||
@ -1,45 +1,49 @@
|
||||
from typing import ForwardRef, Optional
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.test_inheritance_and_pydantic_generation.test_geting_pydantic_models import (
|
||||
Category,
|
||||
SelfRef,
|
||||
database,
|
||||
metadata,
|
||||
) # type: ignore
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
app = FastAPI()
|
||||
app.state.database = database
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
class SelfRef(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy(tablename="self_refs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, default="selfref")
|
||||
parent = ormar.ForeignKey(ForwardRef("SelfRef"), related_name="children")
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
SelfRef.update_forward_refs()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
class Category(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Item(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, default="test")
|
||||
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
async def create_category(category: Category):
|
||||
return await Category(**category.dict()).save()
|
||||
return await Category(**category.model_dump()).save()
|
||||
|
||||
|
||||
create_category.__annotations__["category"] = Category.get_pydantic(exclude={"id"})
|
||||
@ -55,7 +59,7 @@ async def create_selfref(
|
||||
exclude={"children__name"} # noqa: F821
|
||||
),
|
||||
):
|
||||
selfr = SelfRef(**selfref.dict())
|
||||
selfr = SelfRef(**selfref.model_dump())
|
||||
await selfr.save()
|
||||
if selfr.children:
|
||||
for child in selfr.children:
|
||||
@ -107,12 +111,12 @@ async def test_read_main():
|
||||
assert self_ref.id == 3
|
||||
assert self_ref.name == "test3"
|
||||
assert self_ref.parent is None
|
||||
assert self_ref.children[0].dict() == {"id": 4}
|
||||
assert self_ref.children[0].model_dump() == {"id": 4}
|
||||
|
||||
response = await client.get("/selfrefs/3/")
|
||||
assert response.status_code == 200
|
||||
check_children = SelfRef(**response.json())
|
||||
assert check_children.children[0].dict() == {
|
||||
assert check_children.children[0].model_dump() == {
|
||||
"children": [],
|
||||
"id": 4,
|
||||
"name": "selfref",
|
||||
@ -122,9 +126,19 @@ async def test_read_main():
|
||||
response = await client.get("/selfrefs/2/")
|
||||
assert response.status_code == 200
|
||||
check_children = SelfRef(**response.json())
|
||||
assert check_children.dict() == {
|
||||
assert check_children.model_dump() == {
|
||||
"children": [],
|
||||
"id": 2,
|
||||
"name": "test2",
|
||||
"parent": {"id": 1},
|
||||
}
|
||||
|
||||
response = await client.get("/selfrefs/1/")
|
||||
assert response.status_code == 200
|
||||
check_children = SelfRef(**response.json())
|
||||
assert check_children.model_dump() == {
|
||||
"children": [{"id": 2, "name": "test2"}],
|
||||
"id": 1,
|
||||
"name": "test",
|
||||
"parent": None,
|
||||
}
|
||||
|
||||
@ -1,62 +1,34 @@
|
||||
from typing import List
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
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))
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "categories"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Item(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "items"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="items")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
categories: List[Category] = ormar.ManyToMany(Category)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.post("/items/", response_model=Item)
|
||||
@ -68,40 +40,26 @@ async def create_item(item: Item):
|
||||
@app.get("/items/{item_id}")
|
||||
async def get_item(item_id: int):
|
||||
item = await Item.objects.select_related("categories").get(pk=item_id)
|
||||
return item.dict(exclude_primary_keys=True, exclude_through_models=True)
|
||||
return item.model_dump(exclude_primary_keys=True, exclude_through_models=True)
|
||||
|
||||
|
||||
@app.get("/categories/{category_id}")
|
||||
async def get_category(category_id: int):
|
||||
category = await Category.objects.select_related("items").get(pk=category_id)
|
||||
return category.dict(exclude_primary_keys=True)
|
||||
return category.model_dump(exclude_primary_keys=True)
|
||||
|
||||
|
||||
@app.get("/categories/nt/{category_id}")
|
||||
async def get_category_no_through(category_id: int):
|
||||
category = await Category.objects.select_related("items").get(pk=category_id)
|
||||
return category.dict(exclude_through_models=True)
|
||||
result = category.model_dump(exclude_through_models=True)
|
||||
return result
|
||||
|
||||
|
||||
@app.get("/categories/ntp/{category_id}")
|
||||
async def get_category_no_pk_through(category_id: int):
|
||||
category = await Category.objects.select_related("items").get(pk=category_id)
|
||||
return category.dict(exclude_through_models=True, exclude_primary_keys=True)
|
||||
|
||||
|
||||
@app.get(
|
||||
"/items/fex/{item_id}",
|
||||
response_model=Item,
|
||||
response_model_exclude={
|
||||
"id",
|
||||
"categories__id",
|
||||
"categories__itemcategory",
|
||||
"categories__items",
|
||||
},
|
||||
)
|
||||
async def get_item_excl(item_id: int):
|
||||
item = await Item.objects.select_all().get(pk=item_id)
|
||||
return item
|
||||
return category.model_dump(exclude_through_models=True, exclude_primary_keys=True)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@ -120,9 +78,6 @@ async def test_all_endpoints():
|
||||
no_pk_item = (await client.get(f"/items/{item_check.id}")).json()
|
||||
assert no_pk_item == item
|
||||
|
||||
no_pk_item2 = (await client.get(f"/items/fex/{item_check.id}")).json()
|
||||
assert no_pk_item2 == item
|
||||
|
||||
no_pk_category = (
|
||||
await client.get(f"/categories/{item_check.categories[0].id}")
|
||||
).json()
|
||||
|
||||
@ -1,52 +1,25 @@
|
||||
import json
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from ormar import Extra
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
app = FastAPI()
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
app.state.database = database
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
class Item(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
extra = Extra.ignore
|
||||
ormar_config = base_ormar_config.copy(extra=Extra.ignore)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.post("/item/", response_model=Item)
|
||||
|
||||
@ -1,40 +1,19 @@
|
||||
import datetime
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
from pydantic import Field
|
||||
|
||||
import ormar
|
||||
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()
|
||||
|
||||
|
||||
class LocalMeta:
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
class PTestA(pydantic.BaseModel):
|
||||
@ -49,35 +28,31 @@ class PTestP(pydantic.BaseModel):
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta(LocalMeta):
|
||||
tablename = "categories"
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Item(ormar.Model):
|
||||
class Meta(LocalMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
pydantic_int: Optional[int]
|
||||
test_P: Optional[List[PTestP]]
|
||||
pydantic_int: Optional[int] = None
|
||||
test_P: List[PTestP] = Field(default_factory=list)
|
||||
test_P_or_A: Union[int, str, None] = None
|
||||
categories = ormar.ManyToMany(Category)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.get("/items/", response_model=List[Item])
|
||||
async def get_items():
|
||||
items = await Item.objects.select_related("categories").all()
|
||||
for item in items:
|
||||
item.test_P_or_A = 2
|
||||
return items
|
||||
|
||||
|
||||
@ -104,26 +79,35 @@ async def test_all_endpoints():
|
||||
client = AsyncClient(app=app, base_url="http://testserver")
|
||||
async with client as client, LifespanManager(app):
|
||||
response = await client.post("/categories/", json={"name": "test cat"})
|
||||
assert response.status_code == 200
|
||||
category = response.json()
|
||||
response = await client.post("/categories/", json={"name": "test cat2"})
|
||||
assert response.status_code == 200
|
||||
category2 = response.json()
|
||||
|
||||
response = await client.post("/items/", json={"name": "test", "id": 1})
|
||||
response = await client.post(
|
||||
"/items/", json={"name": "test", "id": 1, "test_P_or_A": 0}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
item = Item(**response.json())
|
||||
assert item.pk is not None
|
||||
|
||||
response = await client.post(
|
||||
"/items/add_category/", json={"item": item.dict(), "category": category}
|
||||
"/items/add_category/",
|
||||
json={"item": item.model_dump(), "category": category},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
item = Item(**response.json())
|
||||
assert len(item.categories) == 1
|
||||
assert item.categories[0].name == "test cat"
|
||||
|
||||
await client.post(
|
||||
"/items/add_category/", json={"item": item.dict(), "category": category2}
|
||||
"/items/add_category/",
|
||||
json={"item": item.model_dump(), "category": category2},
|
||||
)
|
||||
|
||||
response = await client.get("/items/")
|
||||
assert response.status_code == 200
|
||||
items = [Item(**item) for item in response.json()]
|
||||
assert items[0] == item
|
||||
assert len(items[0].categories) == 2
|
||||
@ -136,7 +120,7 @@ async def test_all_endpoints():
|
||||
|
||||
|
||||
def test_schema_modification():
|
||||
schema = Item.schema()
|
||||
schema = Item.model_json_schema()
|
||||
assert any(
|
||||
x.get("type") == "array" for x in schema["properties"]["categories"]["anyOf"]
|
||||
)
|
||||
@ -147,10 +131,11 @@ def test_schema_modification():
|
||||
"name": "string",
|
||||
"pydantic_int": 0,
|
||||
"test_P": [{"a": 0, "b": {"c": "string", "d": "string", "e": "string"}}],
|
||||
"test_P_or_A": (0, "string"),
|
||||
}
|
||||
|
||||
schema = Category.schema()
|
||||
assert schema["example"] == {
|
||||
schema = Category.model_json_schema()
|
||||
assert schema["$defs"]["Category"]["example"] == {
|
||||
"id": 0,
|
||||
"name": "string",
|
||||
"items": [
|
||||
@ -161,6 +146,7 @@ def test_schema_modification():
|
||||
"test_P": [
|
||||
{"a": 0, "b": {"c": "string", "d": "string", "e": "string"}}
|
||||
],
|
||||
"test_P_or_A": (0, "string"),
|
||||
}
|
||||
],
|
||||
}
|
||||
@ -169,4 +155,6 @@ def test_schema_modification():
|
||||
def test_schema_gen():
|
||||
schema = app.openapi()
|
||||
assert "Category" in schema["components"]["schemas"]
|
||||
assert "Item" in schema["components"]["schemas"]
|
||||
subschemas = [x.split("__")[-1] for x in schema["components"]["schemas"]]
|
||||
assert "Item-Input" in subschemas
|
||||
assert "Item-Output" in subschemas
|
||||
|
||||
@ -1,42 +1,36 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "categories"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Item(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "items"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="items")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.post("/items/", response_model=Item)
|
||||
async def create_item(item: Item):
|
||||
return item
|
||||
@ -53,7 +47,6 @@ async def test_read_main():
|
||||
assert response.json() == {
|
||||
"category": {
|
||||
"id": None,
|
||||
"items": [{"id": 1, "name": "test"}],
|
||||
"name": "test cat",
|
||||
},
|
||||
"id": 1,
|
||||
@ -61,3 +54,4 @@ async def test_read_main():
|
||||
}
|
||||
item = Item(**response.json())
|
||||
assert item.id == 1
|
||||
assert item.category.items[0].id == 1
|
||||
|
||||
@ -1,41 +1,139 @@
|
||||
import datetime
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
from ormar.relations.relation_proxy import RelationProxy
|
||||
from pydantic import computed_field
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.test_inheritance_and_pydantic_generation.test_inheritance_concrete import ( # type: ignore
|
||||
Category,
|
||||
Subject,
|
||||
Person,
|
||||
Bus,
|
||||
Truck,
|
||||
Bus2,
|
||||
Truck2,
|
||||
db as database,
|
||||
metadata,
|
||||
)
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
app = FastAPI()
|
||||
app.state.database = database
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
class AuditModel(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
created_by: str = ormar.String(max_length=100)
|
||||
updated_by: str = ormar.String(max_length=100, default="Sam")
|
||||
|
||||
@computed_field
|
||||
def audit(self) -> str: # pragma: no cover
|
||||
return f"{self.created_by} {self.updated_by}"
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
class DateFieldsModelNoSubclass(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy(tablename="test_date_models")
|
||||
|
||||
date_id: int = ormar.Integer(primary_key=True)
|
||||
created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
|
||||
|
||||
class DateFieldsModel(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy(
|
||||
abstract=True,
|
||||
constraints=[
|
||||
ormar.fields.constraints.UniqueColumns(
|
||||
"creation_date",
|
||||
"modification_date",
|
||||
),
|
||||
ormar.fields.constraints.CheckColumns(
|
||||
"creation_date <= modification_date",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
created_date: datetime.datetime = ormar.DateTime(
|
||||
default=datetime.datetime.now, name="creation_date"
|
||||
)
|
||||
updated_date: datetime.datetime = ormar.DateTime(
|
||||
default=datetime.datetime.now, name="modification_date"
|
||||
)
|
||||
|
||||
|
||||
class Person(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Car(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50)
|
||||
owner: Person = ormar.ForeignKey(Person)
|
||||
co_owner: Person = ormar.ForeignKey(Person, related_name="coowned")
|
||||
created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
|
||||
|
||||
class Car2(ormar.Model):
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50)
|
||||
owner: Person = ormar.ForeignKey(Person, related_name="owned")
|
||||
co_owners: RelationProxy[Person] = ormar.ManyToMany(Person, related_name="coowned")
|
||||
created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
|
||||
|
||||
class Bus(Car):
|
||||
ormar_config = base_ormar_config.copy(tablename="buses")
|
||||
|
||||
owner: Person = ormar.ForeignKey(Person, related_name="buses")
|
||||
max_persons: int = ormar.Integer()
|
||||
|
||||
|
||||
class Bus2(Car2):
|
||||
ormar_config = base_ormar_config.copy(tablename="buses2")
|
||||
|
||||
max_persons: int = ormar.Integer()
|
||||
|
||||
|
||||
class Category(DateFieldsModel, AuditModel):
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
code: int = ormar.Integer()
|
||||
|
||||
@computed_field
|
||||
def code_name(self) -> str:
|
||||
return f"{self.code}:{self.name}"
|
||||
|
||||
@computed_field
|
||||
def audit(self) -> str:
|
||||
return f"{self.created_by} {self.updated_by}"
|
||||
|
||||
|
||||
class Subject(DateFieldsModel):
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
category: Optional[Category] = ormar.ForeignKey(Category)
|
||||
|
||||
|
||||
class Truck(Car):
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
max_capacity: int = ormar.Integer()
|
||||
|
||||
|
||||
class Truck2(Car2):
|
||||
ormar_config = base_ormar_config.copy(tablename="trucks2")
|
||||
|
||||
max_capacity: int = ormar.Integer()
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.post("/subjects/", response_model=Subject)
|
||||
@ -111,14 +209,6 @@ async def add_truck_coowner(item_id: int, person: Person):
|
||||
return truck
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_main():
|
||||
client = AsyncClient(app=app, base_url="http://testserver")
|
||||
@ -134,7 +224,7 @@ async def test_read_main():
|
||||
assert cat.created_date is not None
|
||||
assert cat.id == 1
|
||||
|
||||
cat_dict = cat.dict()
|
||||
cat_dict = cat.model_dump()
|
||||
cat_dict["updated_date"] = cat_dict["updated_date"].strftime(
|
||||
"%Y-%m-%d %H:%M:%S.%f"
|
||||
)
|
||||
@ -160,11 +250,14 @@ async def test_inheritance_with_relation():
|
||||
truck_dict = dict(
|
||||
name="Shelby wanna be",
|
||||
max_capacity=1400,
|
||||
owner=sam.dict(),
|
||||
co_owner=joe.dict(),
|
||||
owner=sam.model_dump(),
|
||||
co_owner=joe.model_dump(),
|
||||
)
|
||||
bus_dict = dict(
|
||||
name="Unicorn", max_persons=50, owner=sam.dict(), co_owner=joe.dict()
|
||||
name="Unicorn",
|
||||
max_persons=50,
|
||||
owner=sam.model_dump(),
|
||||
co_owner=joe.model_dump(),
|
||||
)
|
||||
unicorn = Bus(**(await client.post("/buses/", json=bus_dict)).json())
|
||||
shelby = Truck(**(await client.post("/trucks/", json=truck_dict)).json())
|
||||
@ -201,21 +294,25 @@ async def test_inheritance_with_m2m_relation():
|
||||
joe = Person(**(await client.post("/persons/", json={"name": "Joe"})).json())
|
||||
alex = Person(**(await client.post("/persons/", json={"name": "Alex"})).json())
|
||||
|
||||
truck_dict = dict(name="Shelby wanna be", max_capacity=2000, owner=sam.dict())
|
||||
bus_dict = dict(name="Unicorn", max_persons=80, owner=sam.dict())
|
||||
truck_dict = dict(
|
||||
name="Shelby wanna be", max_capacity=2000, owner=sam.model_dump()
|
||||
)
|
||||
bus_dict = dict(name="Unicorn", max_persons=80, owner=sam.model_dump())
|
||||
|
||||
unicorn = Bus2(**(await client.post("/buses2/", json=bus_dict)).json())
|
||||
shelby = Truck2(**(await client.post("/trucks2/", json=truck_dict)).json())
|
||||
|
||||
unicorn = Bus2(
|
||||
**(
|
||||
await client.post(f"/buses2/{unicorn.pk}/add_coowner/", json=joe.dict())
|
||||
await client.post(
|
||||
f"/buses2/{unicorn.pk}/add_coowner/", json=joe.model_dump()
|
||||
)
|
||||
).json()
|
||||
)
|
||||
unicorn = Bus2(
|
||||
**(
|
||||
await client.post(
|
||||
f"/buses2/{unicorn.pk}/add_coowner/", json=alex.dict()
|
||||
f"/buses2/{unicorn.pk}/add_coowner/", json=alex.model_dump()
|
||||
)
|
||||
).json()
|
||||
)
|
||||
@ -232,11 +329,13 @@ async def test_inheritance_with_m2m_relation():
|
||||
assert unicorn.co_owners[1] == alex
|
||||
assert unicorn.max_persons == 80
|
||||
|
||||
await client.post(f"/trucks2/{shelby.pk}/add_coowner/", json=alex.dict())
|
||||
await client.post(f"/trucks2/{shelby.pk}/add_coowner/", json=alex.model_dump())
|
||||
|
||||
shelby = Truck2(
|
||||
**(
|
||||
await client.post(f"/trucks2/{shelby.pk}/add_coowner/", json=joe.dict())
|
||||
await client.post(
|
||||
f"/trucks2/{shelby.pk}/add_coowner/", json=joe.model_dump()
|
||||
)
|
||||
).json()
|
||||
)
|
||||
|
||||
|
||||
@ -1,30 +1,46 @@
|
||||
import datetime
|
||||
from typing import Optional
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.test_inheritance_and_pydantic_generation.test_inheritance_mixins import Category, Subject, metadata, db as database # type: ignore
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
app = FastAPI()
|
||||
app.state.database = database
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
class AuditMixin:
|
||||
created_by: str = ormar.String(max_length=100)
|
||||
updated_by: str = ormar.String(max_length=100, default="Sam")
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
class DateFieldsMixins:
|
||||
created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
|
||||
|
||||
class Category(ormar.Model, DateFieldsMixins, AuditMixin):
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
code: int = ormar.Integer()
|
||||
|
||||
|
||||
class Subject(ormar.Model, DateFieldsMixins):
|
||||
ormar_config = base_ormar_config.copy(tablename="subjects")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
category: Optional[Category] = ormar.ForeignKey(Category)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.post("/subjects/", response_model=Subject)
|
||||
@ -38,14 +54,6 @@ async def create_category(category: Category):
|
||||
return category
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_main():
|
||||
client = AsyncClient(app=app, base_url="http://testserver")
|
||||
@ -61,7 +69,7 @@ async def test_read_main():
|
||||
assert cat.created_date is not None
|
||||
assert cat.id == 1
|
||||
|
||||
cat_dict = cat.dict()
|
||||
cat_dict = cat.model_dump()
|
||||
cat_dict["updated_date"] = cat_dict["updated_date"].strftime(
|
||||
"%Y-%m-%d %H:%M:%S.%f"
|
||||
)
|
||||
|
||||
@ -2,52 +2,31 @@
|
||||
import uuid
|
||||
from typing import List
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
app.state.database = database
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
class Thing(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "things"
|
||||
ormar_config = base_ormar_config.copy(tablename="things")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
js: pydantic.Json = ormar.JSON()
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.get("/things", response_model=List[Thing])
|
||||
async def read_things():
|
||||
return await Thing.objects.order_by("name").all()
|
||||
@ -87,14 +66,6 @@ async def read_things_untyped():
|
||||
return await Thing.objects.order_by("name").all()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_json_is_required_if_not_nullable():
|
||||
with pytest.raises(pydantic.ValidationError):
|
||||
@ -104,8 +75,7 @@ async def test_json_is_required_if_not_nullable():
|
||||
@pytest.mark.asyncio
|
||||
async def test_json_is_not_required_if_nullable():
|
||||
class Thing2(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "things2"
|
||||
ormar_config = base_ormar_config.copy(tablename="things2")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
@ -116,16 +86,16 @@ async def test_json_is_not_required_if_nullable():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_setting_values_after_init():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
t1 = Thing(id="67a82813-d90c-45ff-b546-b4e38d7030d7", name="t1", js=["thing1"])
|
||||
assert '["thing1"]' in t1.json()
|
||||
assert '["thing1"]' in t1.model_dump_json()
|
||||
await t1.save()
|
||||
t1.json()
|
||||
assert '["thing1"]' in t1.json()
|
||||
t1.model_dump_json()
|
||||
assert '["thing1"]' in t1.model_dump_json()
|
||||
|
||||
assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).json()
|
||||
assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).model_dump_json()
|
||||
await t1.update()
|
||||
assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).json()
|
||||
assert '["thing1"]' in (await Thing.objects.get(id=t1.id)).model_dump_json()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@ -1,42 +1,17 @@
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from pydantic.schema import ForwardRef
|
||||
from starlette import status
|
||||
from httpx import AsyncClient
|
||||
from typing import ForwardRef, List, Optional
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
from starlette import status
|
||||
|
||||
app = FastAPI()
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
app.state.database = database
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
database = database
|
||||
metadata = metadata
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
CityRef = ForwardRef("City")
|
||||
@ -45,8 +20,7 @@ CountryRef = ForwardRef("Country")
|
||||
|
||||
# models.py
|
||||
class Country(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "countries"
|
||||
ormar_config = base_ormar_config.copy(tablename="countries")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=128, unique=True)
|
||||
@ -64,8 +38,7 @@ class Country(ormar.Model):
|
||||
|
||||
|
||||
class City(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "cities"
|
||||
ormar_config = base_ormar_config.copy(tablename="cities")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=128)
|
||||
@ -77,12 +50,7 @@ class City(ormar.Model):
|
||||
Country.update_forward_refs()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.post("/", response_model=Country, status_code=status.HTTP_201_CREATED)
|
||||
|
||||
@ -1,62 +1,34 @@
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
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))
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "categories"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Item(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "items"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="items")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.get("/items", response_model=List[Item])
|
||||
@ -92,7 +64,7 @@ async def get_item(item_id: int):
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(item_id: int, item: Item):
|
||||
item_db = await Item.objects.get(pk=item_id)
|
||||
return await item_db.update(**item.dict())
|
||||
return await item_db.update(**item.model_dump())
|
||||
|
||||
|
||||
@app.delete("/items/{item_id}")
|
||||
@ -118,8 +90,8 @@ async def test_all_endpoints():
|
||||
assert items[0] == item
|
||||
|
||||
item.name = "New name"
|
||||
response = await client.put(f"/items/{item.pk}", json=item.dict())
|
||||
assert response.json() == item.dict()
|
||||
response = await client.put(f"/items/{item.pk}", json=item.model_dump())
|
||||
assert response.json() == item.model_dump()
|
||||
|
||||
response = await client.get("/items")
|
||||
items = [Item(**item) for item in response.json()]
|
||||
|
||||
@ -1,52 +1,29 @@
|
||||
import json
|
||||
from typing import Any, Dict, Optional, Set, Type, Union, cast
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from ormar.queryset.utils import translate_list_to_dict
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
app = FastAPI()
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
app.state.database = database
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
headers = {"content-type": "application/json"}
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
class Department(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
department_name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Course(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
course_name: str = ormar.String(max_length=100)
|
||||
@ -55,24 +32,13 @@ class Course(ormar.Model):
|
||||
|
||||
|
||||
class Student(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
courses = ormar.ManyToMany(Course)
|
||||
|
||||
|
||||
# create db and tables
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
to_exclude = {
|
||||
"id": ...,
|
||||
"courses": {
|
||||
@ -88,6 +54,9 @@ to_exclude_ormar = {
|
||||
}
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def auto_exclude_id_field(to_exclude: Any) -> Union[Dict, Set]:
|
||||
if isinstance(to_exclude, dict):
|
||||
for key in to_exclude.keys():
|
||||
@ -117,7 +86,7 @@ async def get_department(department_name: str):
|
||||
department = await Department.objects.select_all(follow=True).get(
|
||||
department_name=department_name
|
||||
)
|
||||
return department.dict(exclude=to_exclude)
|
||||
return department.model_dump(exclude=to_exclude)
|
||||
|
||||
|
||||
@app.get("/departments/{department_name}/second")
|
||||
@ -125,7 +94,7 @@ async def get_department_exclude(department_name: str):
|
||||
department = await Department.objects.select_all(follow=True).get(
|
||||
department_name=department_name
|
||||
)
|
||||
return department.dict(exclude=to_exclude_ormar)
|
||||
return department.model_dump(exclude=to_exclude_ormar)
|
||||
|
||||
|
||||
@app.get("/departments/{department_name}/exclude")
|
||||
@ -133,7 +102,7 @@ async def get_department_exclude_all(department_name: str):
|
||||
department = await Department.objects.select_all(follow=True).get(
|
||||
department_name=department_name
|
||||
)
|
||||
return department.dict(exclude=exclude_all)
|
||||
return department.model_dump(exclude=exclude_all)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@ -1,41 +1,22 @@
|
||||
import json
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import Depends, FastAPI
|
||||
from httpx import AsyncClient
|
||||
from pydantic import BaseModel, Json
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
router = FastAPI()
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
router.state.database = database
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
router = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
headers = {"content-type": "application/json"}
|
||||
|
||||
|
||||
@router.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = router.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@router.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = router.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
"""
|
||||
The user model
|
||||
@ -49,10 +30,7 @@ class User(ormar.Model):
|
||||
verify_key: str = ormar.String(unique=True, max_length=100, nullable=True)
|
||||
created_at: datetime = ormar.DateTime(default=datetime.now())
|
||||
|
||||
class Meta:
|
||||
tablename = "users"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="users")
|
||||
|
||||
|
||||
class UserSession(ormar.Model):
|
||||
@ -65,10 +43,7 @@ class UserSession(ormar.Model):
|
||||
session_key: str = ormar.String(unique=True, max_length=64)
|
||||
created_at: datetime = ormar.DateTime(default=datetime.now())
|
||||
|
||||
class Meta:
|
||||
tablename = "user_sessions"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="user_sessions")
|
||||
|
||||
|
||||
class QuizAnswer(BaseModel):
|
||||
@ -96,18 +71,10 @@ class Quiz(ormar.Model):
|
||||
user_id: uuid.UUID = ormar.UUID(foreign_key=User.id)
|
||||
questions: Json = ormar.JSON(nullable=False)
|
||||
|
||||
class Meta:
|
||||
tablename = "quiz"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="quiz")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
async def get_current_user():
|
||||
@ -118,7 +85,7 @@ async def get_current_user():
|
||||
async def create_quiz_lol(
|
||||
quiz_input: QuizInput, user: User = Depends(get_current_user)
|
||||
):
|
||||
quiz = Quiz(**quiz_input.dict(), user_id=user.id)
|
||||
quiz = Quiz(**quiz_input.model_dump(), user_id=user.id)
|
||||
return await quiz.save()
|
||||
|
||||
|
||||
|
||||
@ -1,53 +1,28 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
app = FastAPI()
|
||||
app.state.database = database
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
class Country(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "countries"
|
||||
ormar_config = base_ormar_config.copy(tablename="countries")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, default="Poland")
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -56,8 +31,7 @@ class Author(ormar.Model):
|
||||
|
||||
|
||||
class Book(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
ormar_config = base_ormar_config.copy(tablename="books")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author: Optional[Author] = ormar.ForeignKey(Author)
|
||||
@ -65,17 +39,12 @@ class Book(ormar.Model):
|
||||
year: int = ormar.Integer(nullable=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def sample_data():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
country = await Country(id=1, name="USA").save()
|
||||
author = await Author(id=1, name="bug", rating=5, country=country).save()
|
||||
await Book(
|
||||
@ -101,7 +70,17 @@ async def test_related_with_defaults(sample_data):
|
||||
async with client as client, LifespanManager(app):
|
||||
response = await client.get("/books/1")
|
||||
assert response.json() == {
|
||||
"author": {"id": 1},
|
||||
"author": {
|
||||
"books": [
|
||||
{
|
||||
"author": {"id": 1},
|
||||
"id": 1,
|
||||
"title": "Bug caused by default value",
|
||||
"year": 2021,
|
||||
}
|
||||
],
|
||||
"id": 1,
|
||||
},
|
||||
"id": 1,
|
||||
"title": "Bug caused by default value",
|
||||
"year": 2021,
|
||||
@ -111,9 +90,14 @@ async def test_related_with_defaults(sample_data):
|
||||
assert response.json() == {
|
||||
"author": {
|
||||
"books": [
|
||||
{"id": 1, "title": "Bug caused by default value", "year": 2021}
|
||||
{
|
||||
"author": {"id": 1},
|
||||
"id": 1,
|
||||
"title": "Bug caused by default value",
|
||||
"year": 2021,
|
||||
}
|
||||
],
|
||||
"country": {"id": 1},
|
||||
"country": {"authors": [{"id": 1}], "id": 1},
|
||||
"id": 1,
|
||||
"name": "bug",
|
||||
"rating": 5,
|
||||
|
||||
@ -1,29 +1,24 @@
|
||||
import databases
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
|
||||
DATABASE_URL = "sqlite:///db.sqlite"
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
contents: str = ormar.Text()
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_schema_not_allowed():
|
||||
schema = Author.schema()
|
||||
schema = Author.model_json_schema()
|
||||
for field_schema in schema.get("properties").values():
|
||||
for key in field_schema.keys():
|
||||
assert "_" not in key, f"Found illegal field in openapi schema: {key}"
|
||||
|
||||
@ -1,45 +1,21 @@
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
app = FastAPI()
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
app.state.database = database
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
headers = {"content-type": "application/json"}
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
database = database
|
||||
metadata = metadata
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
first_name: str = ormar.String(max_length=80)
|
||||
@ -47,16 +23,18 @@ class Author(ormar.Model):
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "categories"
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=40)
|
||||
|
||||
|
||||
class Category2(Category):
|
||||
model_config = dict(extra="forbid")
|
||||
|
||||
|
||||
class Post(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
title: str = ormar.String(max_length=200)
|
||||
@ -64,12 +42,12 @@ class Post(ormar.Model):
|
||||
author: Optional[Author] = ormar.ForeignKey(Author, skip_reverse=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.post("/categories/forbid/", response_model=Category2)
|
||||
async def create_category_forbid(category: Category2): # pragma: no cover
|
||||
pass
|
||||
|
||||
|
||||
@app.post("/categories/", response_model=Category)
|
||||
@ -115,7 +93,7 @@ async def test_queries():
|
||||
assert response.status_code == 200
|
||||
response = await client.get("/categories/")
|
||||
assert response.status_code == 200
|
||||
assert not "posts" in response.json()
|
||||
assert "posts" not in response.json()
|
||||
categories = [Category(**x) for x in response.json()]
|
||||
assert categories[0] is not None
|
||||
assert categories[0].name == "Test category2"
|
||||
@ -139,7 +117,7 @@ async def test_queries():
|
||||
response = await client.post("/posts/", json=right_post, headers=headers)
|
||||
assert response.status_code == 200
|
||||
|
||||
Category.__config__.extra = "allow"
|
||||
Category.model_config["extra"] = "allow"
|
||||
response = await client.get("/posts/")
|
||||
assert response.status_code == 200
|
||||
posts = [Post(**x) for x in response.json()]
|
||||
@ -150,6 +128,6 @@ async def test_queries():
|
||||
wrong_category = {"name": "Test category3", "posts": [{"title": "Test Post"}]}
|
||||
|
||||
# cannot add posts if skipped, will be error with extra forbid
|
||||
Category.__config__.extra = "forbid"
|
||||
response = await client.post("/categories/", json=wrong_category)
|
||||
assert Category2.model_config["extra"] == "forbid"
|
||||
response = await client.post("/categories/forbid/", json=wrong_category)
|
||||
assert response.status_code == 422
|
||||
|
||||
@ -1,55 +1,22 @@
|
||||
from typing import List, Optional
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from asgi_lifespan import LifespanManager
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests, lifespan
|
||||
from tests.settings import create_config
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
app.state.database = database
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup() -> None:
|
||||
database_ = app.state.database
|
||||
if not database_.is_connected:
|
||||
await database_.connect()
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown() -> None:
|
||||
database_ = app.state.database
|
||||
if database_.is_connected:
|
||||
await database_.disconnect()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
database = database
|
||||
metadata = metadata
|
||||
base_ormar_config = create_config()
|
||||
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
||||
|
||||
|
||||
class OtherThing(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "other_things"
|
||||
ormar_config = base_ormar_config.copy(tablename="other_things")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
@ -57,8 +24,7 @@ class OtherThing(ormar.Model):
|
||||
|
||||
|
||||
class Thing(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "things"
|
||||
ormar_config = base_ormar_config.copy(tablename="things")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
@ -66,6 +32,9 @@ class Thing(ormar.Model):
|
||||
other_thing: Optional[OtherThing] = ormar.ForeignKey(OtherThing, nullable=True)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@app.post("/test/1")
|
||||
async def post_test_1():
|
||||
# don't split initialization and attribute assignment
|
||||
@ -98,7 +67,7 @@ async def get_test_3():
|
||||
ot = await OtherThing.objects.select_related("things").get()
|
||||
# exclude unwanted field while ot is still in scope
|
||||
# in order not to pass it to fastapi
|
||||
return [t.dict(exclude={"other_thing"}) for t in ot.things]
|
||||
return [t.model_dump(exclude={"other_thing"}) for t in ot.things]
|
||||
|
||||
|
||||
@app.get("/test/4", response_model=List[Thing], response_model_exclude={"other_thing"})
|
||||
|
||||
@ -1,49 +1,37 @@
|
||||
import datetime
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
metadata = sa.MetaData()
|
||||
db = databases.Database(DATABASE_URL)
|
||||
engine = create_engine(DATABASE_URL)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "users"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="users")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
|
||||
|
||||
class RelationalAuditModel(ormar.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
created_by: User = ormar.ForeignKey(User, nullable=False)
|
||||
updated_by: User = ormar.ForeignKey(User, nullable=False)
|
||||
|
||||
|
||||
class AuditModel(ormar.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
created_by: str = ormar.String(max_length=100)
|
||||
updated_by: str = ormar.String(max_length=100, default="Sam")
|
||||
|
||||
|
||||
class DateFieldsModel(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
abstract = True
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
created_date: datetime.datetime = ormar.DateTime(
|
||||
default=datetime.datetime.now, name="creation_date"
|
||||
@ -54,9 +42,10 @@ class DateFieldsModel(ormar.Model):
|
||||
|
||||
|
||||
class Category(DateFieldsModel, AuditModel):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "categories"
|
||||
exclude_parent_fields = ["updated_by", "updated_date"]
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="categories",
|
||||
exclude_parent_fields=["updated_by", "updated_date"],
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
@ -64,9 +53,10 @@ class Category(DateFieldsModel, AuditModel):
|
||||
|
||||
|
||||
class Item(DateFieldsModel, AuditModel):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "items"
|
||||
exclude_parent_fields = ["updated_by", "updated_date"]
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="items",
|
||||
exclude_parent_fields=["updated_by", "updated_date"],
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
@ -75,25 +65,22 @@ class Item(DateFieldsModel, AuditModel):
|
||||
|
||||
|
||||
class Gun(RelationalAuditModel, DateFieldsModel):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "guns"
|
||||
exclude_parent_fields = ["updated_by"]
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="guns",
|
||||
exclude_parent_fields=["updated_by"],
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_model_definition():
|
||||
model_fields = Category.Meta.model_fields
|
||||
sqlalchemy_columns = Category.Meta.table.c
|
||||
pydantic_columns = Category.__fields__
|
||||
model_fields = Category.ormar_config.model_fields
|
||||
sqlalchemy_columns = Category.ormar_config.table.c
|
||||
pydantic_columns = Category.model_fields
|
||||
assert "updated_by" not in model_fields
|
||||
assert "updated_by" not in sqlalchemy_columns
|
||||
assert "updated_by" not in pydantic_columns
|
||||
@ -101,15 +88,15 @@ def test_model_definition():
|
||||
assert "updated_date" not in sqlalchemy_columns
|
||||
assert "updated_date" not in pydantic_columns
|
||||
|
||||
assert "updated_by" not in Gun.Meta.model_fields
|
||||
assert "updated_by" not in Gun.Meta.table.c
|
||||
assert "updated_by" not in Gun.__fields__
|
||||
assert "updated_by" not in Gun.ormar_config.model_fields
|
||||
assert "updated_by" not in Gun.ormar_config.table.c
|
||||
assert "updated_by" not in Gun.model_fields
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_works_as_expected():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
test = await Category(name="Cat", code=2, created_by="Joe").save()
|
||||
assert test.created_date is not None
|
||||
|
||||
@ -120,8 +107,8 @@ async def test_model_works_as_expected():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exclude_with_redefinition():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
test = await Item(name="Item", code=3, created_by="Anna").save()
|
||||
assert test.created_date is not None
|
||||
assert test.updated_by == "Bob"
|
||||
@ -133,8 +120,8 @@ async def test_exclude_with_redefinition():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exclude_with_relation():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
user = await User(name="Michail Kalasznikow").save()
|
||||
test = await Gun(name="AK47", created_by=user).save()
|
||||
assert test.created_date is not None
|
||||
|
||||
@ -1,26 +1,17 @@
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import pydantic
|
||||
import sqlalchemy
|
||||
from pydantic import ConstrainedStr
|
||||
from pydantic.typing import ForwardRef
|
||||
from typing import ForwardRef, List, Optional
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pydantic
|
||||
from pydantic_core import PydanticUndefined
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class SelfRef(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "self_refs"
|
||||
ormar_config = base_ormar_config.copy(tablename="self_refs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, default="selfref")
|
||||
@ -31,16 +22,14 @@ SelfRef.update_forward_refs()
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "categories"
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Item(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, default="test")
|
||||
@ -48,16 +37,14 @@ class Item(ormar.Model):
|
||||
|
||||
|
||||
class MutualA(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "mutual_a"
|
||||
ormar_config = base_ormar_config.copy(tablename="mutual_a")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
mutual_b = ormar.ForeignKey(ForwardRef("MutualB"), related_name="mutuals_a")
|
||||
|
||||
|
||||
class MutualB(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "mutual_b"
|
||||
ormar_config = base_ormar_config.copy(tablename="mutual_b")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name = ormar.String(max_length=100, default="test")
|
||||
@ -67,26 +54,50 @@ class MutualB(ormar.Model):
|
||||
MutualA.update_forward_refs()
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_getting_pydantic_model():
|
||||
PydanticCategory = Category.get_pydantic()
|
||||
assert issubclass(PydanticCategory, pydantic.BaseModel)
|
||||
assert {*PydanticCategory.__fields__.keys()} == {"items", "id", "name"}
|
||||
assert {*PydanticCategory.model_fields.keys()} == {"items", "id", "name"}
|
||||
|
||||
assert not PydanticCategory.__fields__["id"].required
|
||||
assert PydanticCategory.__fields__["id"].outer_type_ == int
|
||||
assert PydanticCategory.__fields__["id"].default is None
|
||||
assert not PydanticCategory.model_fields["id"].is_required()
|
||||
assert (
|
||||
PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["id"]["schema"][
|
||||
"schema"
|
||||
]["schema"]["type"]
|
||||
== "int"
|
||||
)
|
||||
assert PydanticCategory.model_fields["id"].default is None
|
||||
|
||||
assert PydanticCategory.__fields__["name"].required
|
||||
assert issubclass(PydanticCategory.__fields__["name"].outer_type_, ConstrainedStr)
|
||||
assert PydanticCategory.__fields__["name"].default in [None, Ellipsis]
|
||||
assert PydanticCategory.model_fields["name"].is_required()
|
||||
assert (
|
||||
PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["name"]["schema"][
|
||||
"type"
|
||||
]
|
||||
== "str"
|
||||
)
|
||||
assert PydanticCategory.model_fields["name"].default == PydanticUndefined
|
||||
|
||||
PydanticItem = PydanticCategory.__fields__["items"].type_
|
||||
assert PydanticCategory.__fields__["items"].outer_type_ == List[PydanticItem]
|
||||
PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][
|
||||
"items"
|
||||
]["schema"]["schema"]["schema"]["items_schema"]["cls"]
|
||||
assert (
|
||||
PydanticCategory.__pydantic_core_schema__["schema"]["fields"]["items"][
|
||||
"schema"
|
||||
]["schema"]["schema"]["type"]
|
||||
== "list"
|
||||
)
|
||||
assert (
|
||||
PydanticCategory.model_fields["items"].annotation
|
||||
== Optional[List[PydanticItem]]
|
||||
)
|
||||
assert issubclass(PydanticItem, pydantic.BaseModel)
|
||||
assert not PydanticItem.__fields__["name"].required
|
||||
assert PydanticItem.__fields__["name"].default == "test"
|
||||
assert issubclass(PydanticItem.__fields__["name"].outer_type_, ConstrainedStr)
|
||||
assert "category" not in PydanticItem.__fields__
|
||||
assert not PydanticItem.model_fields["name"].is_required()
|
||||
assert PydanticItem.model_fields["name"].default == "test"
|
||||
assert PydanticItem.model_fields["name"].annotation == Optional[str]
|
||||
assert "category" not in PydanticItem.model_fields
|
||||
|
||||
|
||||
def test_initializing_pydantic_model():
|
||||
@ -96,140 +107,199 @@ def test_initializing_pydantic_model():
|
||||
"items": [{"id": 1, "name": "test_i1"}, {"id": 2, "name": "test_i2"}],
|
||||
}
|
||||
PydanticCategory = Category.get_pydantic()
|
||||
ormar_cat = Category(**data)
|
||||
assert ormar_cat.model_dump() == data
|
||||
cat = PydanticCategory(**data)
|
||||
assert cat.dict() == data
|
||||
assert cat.model_dump() == data
|
||||
|
||||
data = {"id": 1, "name": "test"}
|
||||
cat = PydanticCategory(**data)
|
||||
assert cat.dict() == {**data, "items": None}
|
||||
assert cat.model_dump() == {**data, "items": None}
|
||||
|
||||
|
||||
def test_getting_pydantic_model_include():
|
||||
PydanticCategory = Category.get_pydantic(include={"id", "name"})
|
||||
assert len(PydanticCategory.__fields__) == 2
|
||||
assert "items" not in PydanticCategory.__fields__
|
||||
assert len(PydanticCategory.model_fields) == 2
|
||||
assert "items" not in PydanticCategory.model_fields
|
||||
|
||||
|
||||
def test_getting_pydantic_model_nested_include_set():
|
||||
PydanticCategory = Category.get_pydantic(include={"id", "items__id"})
|
||||
assert len(PydanticCategory.__fields__) == 2
|
||||
assert "name" not in PydanticCategory.__fields__
|
||||
PydanticItem = PydanticCategory.__fields__["items"].type_
|
||||
assert len(PydanticItem.__fields__) == 1
|
||||
assert "id" in PydanticItem.__fields__
|
||||
assert len(PydanticCategory.model_fields) == 2
|
||||
assert "name" not in PydanticCategory.model_fields
|
||||
PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][
|
||||
"items"
|
||||
]["schema"]["schema"]["schema"]["items_schema"]["cls"]
|
||||
assert len(PydanticItem.model_fields) == 1
|
||||
assert "id" in PydanticItem.model_fields
|
||||
|
||||
|
||||
def test_getting_pydantic_model_nested_include_dict():
|
||||
PydanticCategory = Category.get_pydantic(include={"id": ..., "items": {"id"}})
|
||||
assert len(PydanticCategory.__fields__) == 2
|
||||
assert "name" not in PydanticCategory.__fields__
|
||||
PydanticItem = PydanticCategory.__fields__["items"].type_
|
||||
assert len(PydanticItem.__fields__) == 1
|
||||
assert "id" in PydanticItem.__fields__
|
||||
assert len(PydanticCategory.model_fields) == 2
|
||||
assert "name" not in PydanticCategory.model_fields
|
||||
PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][
|
||||
"items"
|
||||
]["schema"]["schema"]["schema"]["items_schema"]["cls"]
|
||||
assert len(PydanticItem.model_fields) == 1
|
||||
assert "id" in PydanticItem.model_fields
|
||||
|
||||
|
||||
def test_getting_pydantic_model_nested_include_nested_dict():
|
||||
PydanticCategory = Category.get_pydantic(include={"id": ..., "items": {"id": ...}})
|
||||
assert len(PydanticCategory.__fields__) == 2
|
||||
assert "name" not in PydanticCategory.__fields__
|
||||
PydanticItem = PydanticCategory.__fields__["items"].type_
|
||||
assert len(PydanticItem.__fields__) == 1
|
||||
assert "id" in PydanticItem.__fields__
|
||||
assert len(PydanticCategory.model_fields) == 2
|
||||
assert "name" not in PydanticCategory.model_fields
|
||||
PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][
|
||||
"items"
|
||||
]["schema"]["schema"]["schema"]["items_schema"]["cls"]
|
||||
assert len(PydanticItem.model_fields) == 1
|
||||
assert "id" in PydanticItem.model_fields
|
||||
|
||||
|
||||
def test_getting_pydantic_model_include_exclude():
|
||||
PydanticCategory = Category.get_pydantic(
|
||||
include={"id": ..., "items": {"id", "name"}}, exclude={"items__name"}
|
||||
)
|
||||
assert len(PydanticCategory.__fields__) == 2
|
||||
assert "name" not in PydanticCategory.__fields__
|
||||
PydanticItem = PydanticCategory.__fields__["items"].type_
|
||||
assert len(PydanticItem.__fields__) == 1
|
||||
assert "id" in PydanticItem.__fields__
|
||||
assert len(PydanticCategory.model_fields) == 2
|
||||
assert "name" not in PydanticCategory.model_fields
|
||||
PydanticItem = PydanticCategory.__pydantic_core_schema__["schema"]["fields"][
|
||||
"items"
|
||||
]["schema"]["schema"]["schema"]["items_schema"]["cls"]
|
||||
assert len(PydanticItem.model_fields) == 1
|
||||
assert "id" in PydanticItem.model_fields
|
||||
|
||||
|
||||
def test_getting_pydantic_model_exclude():
|
||||
PydanticItem = Item.get_pydantic(exclude={"category__name"})
|
||||
assert len(PydanticItem.__fields__) == 3
|
||||
assert "category" in PydanticItem.__fields__
|
||||
PydanticCategory = PydanticItem.__fields__["category"].type_
|
||||
assert len(PydanticCategory.__fields__) == 1
|
||||
assert "name" not in PydanticCategory.__fields__
|
||||
assert len(PydanticItem.model_fields) == 3
|
||||
assert "category" in PydanticItem.model_fields
|
||||
PydanticCategory = PydanticItem.__pydantic_core_schema__["schema"]["fields"][
|
||||
"category"
|
||||
]["schema"]["schema"]["schema"]["cls"]
|
||||
assert len(PydanticCategory.model_fields) == 1
|
||||
assert "name" not in PydanticCategory.model_fields
|
||||
|
||||
|
||||
def test_getting_pydantic_model_exclude_dict():
|
||||
PydanticItem = Item.get_pydantic(exclude={"id": ..., "category": {"name"}})
|
||||
assert len(PydanticItem.__fields__) == 2
|
||||
assert "category" in PydanticItem.__fields__
|
||||
assert "id" not in PydanticItem.__fields__
|
||||
PydanticCategory = PydanticItem.__fields__["category"].type_
|
||||
assert len(PydanticCategory.__fields__) == 1
|
||||
assert "name" not in PydanticCategory.__fields__
|
||||
assert len(PydanticItem.model_fields) == 2
|
||||
assert "category" in PydanticItem.model_fields
|
||||
assert "id" not in PydanticItem.model_fields
|
||||
PydanticCategory = PydanticItem.__pydantic_core_schema__["schema"]["fields"][
|
||||
"category"
|
||||
]["schema"]["schema"]["schema"]["cls"]
|
||||
assert len(PydanticCategory.model_fields) == 1
|
||||
assert "name" not in PydanticCategory.model_fields
|
||||
|
||||
|
||||
def test_getting_pydantic_model_self_ref():
|
||||
PydanticSelfRef = SelfRef.get_pydantic()
|
||||
assert len(PydanticSelfRef.__fields__) == 4
|
||||
assert set(PydanticSelfRef.__fields__.keys()) == {
|
||||
assert len(PydanticSelfRef.model_fields) == 4
|
||||
assert set(PydanticSelfRef.model_fields.keys()) == {
|
||||
"id",
|
||||
"name",
|
||||
"parent",
|
||||
"children",
|
||||
}
|
||||
InnerSelf = PydanticSelfRef.__fields__["parent"].type_
|
||||
assert len(InnerSelf.__fields__) == 2
|
||||
assert set(InnerSelf.__fields__.keys()) == {"id", "name"}
|
||||
inner_self_ref_id = PydanticSelfRef.__pydantic_core_schema__["schema"]["schema"][
|
||||
"fields"
|
||||
]["parent"]["schema"]["schema"]["schema"]["schema_ref"]
|
||||
InnerSelf = next(
|
||||
(
|
||||
x
|
||||
for x in PydanticSelfRef.__pydantic_core_schema__["definitions"]
|
||||
if x["ref"] == inner_self_ref_id
|
||||
)
|
||||
)["cls"]
|
||||
assert len(InnerSelf.model_fields) == 2
|
||||
assert set(InnerSelf.model_fields.keys()) == {"id", "name"}
|
||||
|
||||
InnerSelf2 = PydanticSelfRef.__fields__["children"].type_
|
||||
assert len(InnerSelf2.__fields__) == 2
|
||||
assert set(InnerSelf2.__fields__.keys()) == {"id", "name"}
|
||||
inner_self_ref_id2 = PydanticSelfRef.__pydantic_core_schema__["schema"]["schema"][
|
||||
"fields"
|
||||
]["children"]["schema"]["schema"]["schema"]["items_schema"]["schema_ref"]
|
||||
InnerSelf2 = next(
|
||||
(
|
||||
x
|
||||
for x in PydanticSelfRef.__pydantic_core_schema__["definitions"]
|
||||
if x["ref"] == inner_self_ref_id2
|
||||
)
|
||||
)["cls"]
|
||||
assert len(InnerSelf2.model_fields) == 2
|
||||
assert set(InnerSelf2.model_fields.keys()) == {"id", "name"}
|
||||
|
||||
|
||||
def test_getting_pydantic_model_self_ref_exclude():
|
||||
PydanticSelfRef = SelfRef.get_pydantic(exclude={"children": {"name"}})
|
||||
assert len(PydanticSelfRef.__fields__) == 4
|
||||
assert set(PydanticSelfRef.__fields__.keys()) == {
|
||||
assert len(PydanticSelfRef.model_fields) == 4
|
||||
assert set(PydanticSelfRef.model_fields.keys()) == {
|
||||
"id",
|
||||
"name",
|
||||
"parent",
|
||||
"children",
|
||||
}
|
||||
|
||||
InnerSelf = PydanticSelfRef.__fields__["parent"].type_
|
||||
assert len(InnerSelf.__fields__) == 2
|
||||
assert set(InnerSelf.__fields__.keys()) == {"id", "name"}
|
||||
InnerSelf = PydanticSelfRef.__pydantic_core_schema__["schema"]["fields"]["parent"][
|
||||
"schema"
|
||||
]["schema"]["schema"]["cls"]
|
||||
assert len(InnerSelf.model_fields) == 2
|
||||
assert set(InnerSelf.model_fields.keys()) == {"id", "name"}
|
||||
|
||||
PydanticSelfRefChildren = PydanticSelfRef.__fields__["children"].type_
|
||||
assert len(PydanticSelfRefChildren.__fields__) == 1
|
||||
assert set(PydanticSelfRefChildren.__fields__.keys()) == {"id"}
|
||||
# PydanticSelfRefChildren = PydanticSelfRef.model_fields["children"].type_
|
||||
PydanticSelfRefChildren = PydanticSelfRef.__pydantic_core_schema__["schema"][
|
||||
"fields"
|
||||
]["children"]["schema"]["schema"]["schema"]["items_schema"]["cls"]
|
||||
assert len(PydanticSelfRefChildren.model_fields) == 1
|
||||
assert set(PydanticSelfRefChildren.model_fields.keys()) == {"id"}
|
||||
assert PydanticSelfRef != PydanticSelfRefChildren
|
||||
assert InnerSelf != PydanticSelfRefChildren
|
||||
|
||||
|
||||
def test_getting_pydantic_model_mutual_rels():
|
||||
MutualAPydantic = MutualA.get_pydantic()
|
||||
assert len(MutualAPydantic.__fields__) == 3
|
||||
assert set(MutualAPydantic.__fields__.keys()) == {"id", "mutual_b", "mutuals_b"}
|
||||
assert len(MutualAPydantic.model_fields) == 3
|
||||
assert set(MutualAPydantic.model_fields.keys()) == {"id", "mutual_b", "mutuals_b"}
|
||||
|
||||
MutualB1 = MutualAPydantic.__fields__["mutual_b"].type_
|
||||
MutualB2 = MutualAPydantic.__fields__["mutuals_b"].type_
|
||||
assert len(MutualB1.__fields__) == 2
|
||||
assert set(MutualB1.__fields__.keys()) == {"id", "name"}
|
||||
assert len(MutualB2.__fields__) == 2
|
||||
assert set(MutualB2.__fields__.keys()) == {"id", "name"}
|
||||
mutual_ref_1 = MutualAPydantic.__pydantic_core_schema__["schema"]["schema"][
|
||||
"fields"
|
||||
]["mutual_b"]["schema"]["schema"]["schema"]["schema_ref"]
|
||||
MutualB1 = next(
|
||||
(
|
||||
x
|
||||
for x in MutualAPydantic.__pydantic_core_schema__["definitions"]
|
||||
if x["ref"] == mutual_ref_1
|
||||
)
|
||||
)["cls"]
|
||||
mutual_ref_2 = MutualAPydantic.__pydantic_core_schema__["schema"]["schema"][
|
||||
"fields"
|
||||
]["mutuals_b"]["schema"]["schema"]["schema"]["items_schema"]["schema_ref"]
|
||||
MutualB2 = next(
|
||||
(
|
||||
x
|
||||
for x in MutualAPydantic.__pydantic_core_schema__["definitions"]
|
||||
if x["ref"] == mutual_ref_2
|
||||
)
|
||||
)["cls"]
|
||||
assert len(MutualB1.model_fields) == 2
|
||||
assert set(MutualB1.model_fields.keys()) == {"id", "name"}
|
||||
assert len(MutualB2.model_fields) == 2
|
||||
assert set(MutualB2.model_fields.keys()) == {"id", "name"}
|
||||
assert MutualB1 == MutualB2
|
||||
|
||||
|
||||
def test_getting_pydantic_model_mutual_rels_exclude():
|
||||
MutualAPydantic = MutualA.get_pydantic(exclude={"mutual_b": {"name"}})
|
||||
assert len(MutualAPydantic.__fields__) == 3
|
||||
assert set(MutualAPydantic.__fields__.keys()) == {"id", "mutual_b", "mutuals_b"}
|
||||
assert len(MutualAPydantic.model_fields) == 3
|
||||
assert set(MutualAPydantic.model_fields.keys()) == {"id", "mutual_b", "mutuals_b"}
|
||||
|
||||
MutualB1 = MutualAPydantic.__fields__["mutual_b"].type_
|
||||
MutualB2 = MutualAPydantic.__fields__["mutuals_b"].type_
|
||||
MutualB1 = MutualAPydantic.__pydantic_core_schema__["schema"]["fields"]["mutual_b"][
|
||||
"schema"
|
||||
]["schema"]["schema"]["cls"]
|
||||
MutualB2 = MutualAPydantic.__pydantic_core_schema__["schema"]["fields"][
|
||||
"mutuals_b"
|
||||
]["schema"]["schema"]["schema"]["items_schema"]["cls"]
|
||||
|
||||
assert len(MutualB1.__fields__) == 1
|
||||
assert set(MutualB1.__fields__.keys()) == {"id"}
|
||||
assert len(MutualB2.__fields__) == 2
|
||||
assert set(MutualB2.__fields__.keys()) == {"id", "name"}
|
||||
assert len(MutualB1.model_fields) == 1
|
||||
assert set(MutualB1.model_fields.keys()) == {"id"}
|
||||
assert len(MutualB2.model_fields) == 2
|
||||
assert set(MutualB2.model_fields.keys()) == {"id", "name"}
|
||||
assert MutualB1 != MutualB2
|
||||
|
||||
@ -1,42 +1,37 @@
|
||||
# type: ignore
|
||||
import datetime
|
||||
from typing import List, Optional
|
||||
from collections import Counter
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import create_engine
|
||||
from typing import Optional
|
||||
|
||||
import ormar
|
||||
import ormar.fields.constraints
|
||||
from ormar import ModelDefinitionError, property_field
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy as sa
|
||||
from ormar import ModelDefinitionError
|
||||
from ormar.exceptions import ModelError
|
||||
from ormar.models.metaclass import get_constraint_copy
|
||||
from tests.settings import DATABASE_URL
|
||||
from ormar.relations.relation_proxy import RelationProxy
|
||||
from pydantic import computed_field
|
||||
|
||||
metadata = sa.MetaData()
|
||||
db = databases.Database(DATABASE_URL)
|
||||
engine = create_engine(DATABASE_URL)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class AuditModel(ormar.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
created_by: str = ormar.String(max_length=100)
|
||||
updated_by: str = ormar.String(max_length=100, default="Sam")
|
||||
|
||||
@property_field
|
||||
def audit(self): # pragma: no cover
|
||||
@computed_field
|
||||
def audit(self) -> str: # pragma: no cover
|
||||
return f"{self.created_by} {self.updated_by}"
|
||||
|
||||
|
||||
class DateFieldsModelNoSubclass(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "test_date_models"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="test_date_models")
|
||||
|
||||
date_id: int = ormar.Integer(primary_key=True)
|
||||
created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
@ -44,11 +39,9 @@ class DateFieldsModelNoSubclass(ormar.Model):
|
||||
|
||||
|
||||
class DateFieldsModel(ormar.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
metadata = metadata
|
||||
database = db
|
||||
constraints = [
|
||||
ormar_config = base_ormar_config.copy(
|
||||
abstract=True,
|
||||
constraints=[
|
||||
ormar.fields.constraints.UniqueColumns(
|
||||
"creation_date",
|
||||
"modification_date",
|
||||
@ -56,7 +49,8 @@ class DateFieldsModel(ormar.Model):
|
||||
ormar.fields.constraints.CheckColumns(
|
||||
"creation_date <= modification_date",
|
||||
),
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
created_date: datetime.datetime = ormar.DateTime(
|
||||
default=datetime.datetime.now, name="creation_date"
|
||||
@ -67,26 +61,26 @@ class DateFieldsModel(ormar.Model):
|
||||
|
||||
|
||||
class Category(DateFieldsModel, AuditModel):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "categories"
|
||||
constraints = [ormar.fields.constraints.UniqueColumns("name", "code")]
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="categories",
|
||||
constraints=[ormar.fields.constraints.UniqueColumns("name", "code")],
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
code: int = ormar.Integer()
|
||||
|
||||
@property_field
|
||||
def code_name(self):
|
||||
@computed_field
|
||||
def code_name(self) -> str:
|
||||
return f"{self.code}:{self.name}"
|
||||
|
||||
@property_field
|
||||
def audit(self):
|
||||
@computed_field
|
||||
def audit(self) -> str:
|
||||
return f"{self.created_by} {self.updated_by}"
|
||||
|
||||
|
||||
class Subject(DateFieldsModel):
|
||||
class Meta(ormar.ModelMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
@ -94,19 +88,14 @@ class Subject(DateFieldsModel):
|
||||
|
||||
|
||||
class Person(ormar.Model):
|
||||
class Meta:
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Car(ormar.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50)
|
||||
@ -116,135 +105,109 @@ class Car(ormar.Model):
|
||||
|
||||
|
||||
class Truck(Car):
|
||||
class Meta:
|
||||
pass
|
||||
ormar_config = ormar.OrmarConfig()
|
||||
|
||||
max_capacity: int = ormar.Integer()
|
||||
|
||||
|
||||
class Bus(Car):
|
||||
class Meta:
|
||||
tablename = "buses"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="buses")
|
||||
|
||||
owner: Person = ormar.ForeignKey(Person, related_name="buses")
|
||||
max_persons: int = ormar.Integer()
|
||||
|
||||
|
||||
class Car2(ormar.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50)
|
||||
owner: Person = ormar.ForeignKey(Person, related_name="owned")
|
||||
co_owners: List[Person] = ormar.ManyToMany(Person, related_name="coowned")
|
||||
co_owners: RelationProxy[Person] = ormar.ManyToMany(Person, related_name="coowned")
|
||||
created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
|
||||
|
||||
class Truck2(Car2):
|
||||
class Meta:
|
||||
tablename = "trucks2"
|
||||
ormar_config = base_ormar_config.copy(tablename="trucks2")
|
||||
|
||||
max_capacity: int = ormar.Integer()
|
||||
|
||||
|
||||
class Bus2(Car2):
|
||||
class Meta:
|
||||
tablename = "buses2"
|
||||
ormar_config = base_ormar_config.copy(tablename="buses2")
|
||||
|
||||
max_persons: int = ormar.Integer()
|
||||
|
||||
|
||||
class ImmutablePerson(Person):
|
||||
class Config:
|
||||
allow_mutation = False
|
||||
validate_assignment = False
|
||||
model_config = dict(frozen=True, validate_assignment=False)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_init_of_abstract_model():
|
||||
def test_init_of_abstract_model() -> None:
|
||||
with pytest.raises(ModelError):
|
||||
DateFieldsModel()
|
||||
|
||||
|
||||
def test_duplicated_related_name_on_different_model():
|
||||
def test_duplicated_related_name_on_different_model() -> None:
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class Bus3(Car2): # pragma: no cover
|
||||
class Meta:
|
||||
tablename = "buses3"
|
||||
ormar_config = ormar.OrmarConfig(tablename="buses3")
|
||||
|
||||
owner: Person = ormar.ForeignKey(Person, related_name="buses")
|
||||
max_persons: int = ormar.Integer()
|
||||
|
||||
|
||||
def test_config_is_not_a_class_raises_error():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class ImmutablePerson2(Person):
|
||||
Config = dict(allow_mutation=False, validate_assignment=False)
|
||||
|
||||
|
||||
def test_field_redefining_in_concrete_models():
|
||||
def test_field_redefining_in_concrete_models() -> None:
|
||||
class RedefinedField(DateFieldsModel):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "redefines"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="redefines")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
created_date: str = ormar.String(max_length=200, name="creation_date")
|
||||
created_date: str = ormar.String(
|
||||
max_length=200,
|
||||
name="creation_date",
|
||||
) # type: ignore
|
||||
|
||||
changed_field = RedefinedField.Meta.model_fields["created_date"]
|
||||
changed_field = RedefinedField.ormar_config.model_fields["created_date"]
|
||||
assert changed_field.ormar_default is None
|
||||
assert changed_field.get_alias() == "creation_date"
|
||||
assert any(x.name == "creation_date" for x in RedefinedField.Meta.table.columns)
|
||||
assert any(
|
||||
x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns
|
||||
)
|
||||
assert isinstance(
|
||||
RedefinedField.Meta.table.columns["creation_date"].type, sa.sql.sqltypes.String
|
||||
RedefinedField.ormar_config.table.columns["creation_date"].type,
|
||||
sa.sql.sqltypes.String,
|
||||
)
|
||||
|
||||
|
||||
def test_model_subclassing_that_redefines_constraints_column_names():
|
||||
def test_model_subclassing_that_redefines_constraints_column_names() -> None:
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class WrongField2(DateFieldsModel): # pragma: no cover
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "wrongs"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="wrongs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
created_date: str = ormar.String(max_length=200)
|
||||
created_date: str = ormar.String(max_length=200) # type: ignore
|
||||
|
||||
|
||||
def test_model_subclassing_non_abstract_raises_error():
|
||||
def test_model_subclassing_non_abstract_raises_error() -> None:
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class WrongField2(DateFieldsModelNoSubclass): # pragma: no cover
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "wrongs"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="wrongs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
|
||||
|
||||
def test_params_are_inherited():
|
||||
assert Category.Meta.metadata == metadata
|
||||
assert Category.Meta.database == db
|
||||
assert len(Category.Meta.property_fields) == 2
|
||||
def test_params_are_inherited() -> None:
|
||||
assert Category.ormar_config.metadata == base_ormar_config.metadata
|
||||
assert Category.ormar_config.database == base_ormar_config.database
|
||||
assert len(Category.ormar_config.property_fields) == 2
|
||||
|
||||
constraints = Counter(map(lambda c: type(c), Category.Meta.constraints))
|
||||
constraints = Counter(map(lambda c: type(c), Category.ormar_config.constraints))
|
||||
assert constraints[ormar.fields.constraints.UniqueColumns] == 2
|
||||
assert constraints[ormar.fields.constraints.IndexColumns] == 0
|
||||
assert constraints[ormar.fields.constraints.CheckColumns] == 1
|
||||
@ -259,9 +222,9 @@ def round_date_to_seconds(
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fields_inherited_from_mixin():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async def test_fields_inherited_from_mixin() -> None:
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
cat = await Category(
|
||||
name="Foo", code=123, created_by="Sam", updated_by="Max"
|
||||
).save()
|
||||
@ -269,19 +232,28 @@ async def test_fields_inherited_from_mixin():
|
||||
mixin_columns = ["created_date", "updated_date"]
|
||||
mixin_db_columns = ["creation_date", "modification_date"]
|
||||
mixin2_columns = ["created_by", "updated_by"]
|
||||
assert all(field in Category.Meta.model_fields for field in mixin_columns)
|
||||
assert all(
|
||||
field in Category.ormar_config.model_fields for field in mixin_columns
|
||||
)
|
||||
assert cat.created_date is not None
|
||||
assert cat.updated_date is not None
|
||||
assert all(field in Subject.Meta.model_fields for field in mixin_columns)
|
||||
assert all(
|
||||
field in Subject.ormar_config.model_fields for field in mixin_columns
|
||||
)
|
||||
assert cat.code_name == "123:Foo"
|
||||
assert cat.audit == "Sam Max"
|
||||
assert sub.created_date is not None
|
||||
assert sub.updated_date is not None
|
||||
|
||||
assert all(field in Category.Meta.model_fields for field in mixin2_columns)
|
||||
assert all(
|
||||
field not in Subject.Meta.model_fields for field in mixin2_columns
|
||||
field in Category.ormar_config.model_fields for field in mixin2_columns
|
||||
)
|
||||
assert all(
|
||||
field not in Subject.ormar_config.model_fields
|
||||
for field in mixin2_columns
|
||||
)
|
||||
|
||||
inspector = sa.inspect(engine)
|
||||
inspector = sa.inspect(base_ormar_config.engine)
|
||||
assert "categories" in inspector.get_table_names()
|
||||
table_columns = [x.get("name") for x in inspector.get_columns("categories")]
|
||||
assert all(
|
||||
@ -301,6 +273,7 @@ async def test_fields_inherited_from_mixin():
|
||||
assert round_date_to_seconds(sub2.created_date) == round_date_to_seconds(
|
||||
sub.created_date
|
||||
)
|
||||
assert sub2.category is not None
|
||||
assert sub2.category.updated_date is not None
|
||||
assert round_date_to_seconds(
|
||||
sub2.category.created_date
|
||||
@ -328,9 +301,9 @@ async def test_fields_inherited_from_mixin():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_inheritance_with_relation():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async def test_inheritance_with_relation() -> None:
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
sam = await Person(name="Sam").save()
|
||||
joe = await Person(name="Joe").save()
|
||||
await Truck(
|
||||
@ -377,9 +350,9 @@ async def test_inheritance_with_relation():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_inheritance_with_multi_relation():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async def test_inheritance_with_multi_relation() -> None:
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
sam = await Person(name="Sam").save()
|
||||
joe = await Person(name="Joe").save()
|
||||
alex = await Person(name="Alex").save()
|
||||
@ -523,16 +496,16 @@ async def test_inheritance_with_multi_relation():
|
||||
assert len(unicorns[1].co_owners) == 1
|
||||
|
||||
|
||||
def test_custom_config():
|
||||
def test_custom_config() -> None:
|
||||
# Custom config inherits defaults
|
||||
assert getattr(ImmutablePerson.__config__, "orm_mode") is True
|
||||
assert ImmutablePerson.model_config["from_attributes"] is True
|
||||
# Custom config can override defaults
|
||||
assert getattr(ImmutablePerson.__config__, "validate_assignment") is False
|
||||
assert ImmutablePerson.model_config["validate_assignment"] is False
|
||||
sam = ImmutablePerson(name="Sam")
|
||||
with pytest.raises(TypeError):
|
||||
with pytest.raises(pydantic.ValidationError):
|
||||
sam.name = "Not Sam"
|
||||
|
||||
|
||||
def test_get_constraint_copy():
|
||||
def test_get_constraint_copy() -> None:
|
||||
with pytest.raises(ValueError):
|
||||
get_constraint_copy("INVALID CONSTRAINT")
|
||||
|
||||
@ -1,18 +1,14 @@
|
||||
# type: ignore
|
||||
import datetime
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
metadata = sa.MetaData()
|
||||
db = databases.Database(DATABASE_URL)
|
||||
engine = create_engine(DATABASE_URL)
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class AuditMixin:
|
||||
@ -26,10 +22,7 @@ class DateFieldsMixins:
|
||||
|
||||
|
||||
class Category(ormar.Model, DateFieldsMixins, AuditMixin):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "categories"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
@ -37,65 +30,59 @@ class Category(ormar.Model, DateFieldsMixins, AuditMixin):
|
||||
|
||||
|
||||
class Subject(ormar.Model, DateFieldsMixins):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "subjects"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="subjects")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
category: Optional[Category] = ormar.ForeignKey(Category)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_field_redefining():
|
||||
def test_field_redefining() -> None:
|
||||
class RedefinedField(ormar.Model, DateFieldsMixins):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "redefined"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="redefined")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
created_date: datetime.datetime = ormar.DateTime(name="creation_date")
|
||||
|
||||
assert RedefinedField.Meta.model_fields["created_date"].ormar_default is None
|
||||
assert (
|
||||
RedefinedField.Meta.model_fields["created_date"].get_alias() == "creation_date"
|
||||
RedefinedField.ormar_config.model_fields["created_date"].ormar_default is None
|
||||
)
|
||||
assert (
|
||||
RedefinedField.ormar_config.model_fields["created_date"].get_alias()
|
||||
== "creation_date"
|
||||
)
|
||||
assert any(
|
||||
x.name == "creation_date" for x in RedefinedField.ormar_config.table.columns
|
||||
)
|
||||
assert any(x.name == "creation_date" for x in RedefinedField.Meta.table.columns)
|
||||
|
||||
|
||||
def test_field_redefining_in_second_raises_error():
|
||||
class OkField(ormar.Model, DateFieldsMixins): # pragma: no cover
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "oks"
|
||||
metadata = metadata
|
||||
database = db
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
def test_field_redefining_in_second() -> None:
|
||||
|
||||
class RedefinedField2(ormar.Model, DateFieldsMixins):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "redefines2"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = base_ormar_config.copy(tablename="redefines2")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
created_date: str = ormar.String(max_length=200, name="creation_date")
|
||||
created_date: str = ormar.String(
|
||||
max_length=200,
|
||||
name="creation_date",
|
||||
) # type: ignore
|
||||
|
||||
assert RedefinedField2.Meta.model_fields["created_date"].ormar_default is None
|
||||
assert (
|
||||
RedefinedField2.Meta.model_fields["created_date"].get_alias() == "creation_date"
|
||||
RedefinedField2.ormar_config.model_fields["created_date"].ormar_default is None
|
||||
)
|
||||
assert (
|
||||
RedefinedField2.ormar_config.model_fields["created_date"].get_alias()
|
||||
== "creation_date"
|
||||
)
|
||||
assert any(
|
||||
x.name == "creation_date" for x in RedefinedField2.ormar_config.table.columns
|
||||
)
|
||||
assert any(x.name == "creation_date" for x in RedefinedField2.Meta.table.columns)
|
||||
assert isinstance(
|
||||
RedefinedField2.Meta.table.columns["creation_date"].type, sa.sql.sqltypes.String
|
||||
RedefinedField2.ormar_config.table.columns["creation_date"].type,
|
||||
sa.sql.sqltypes.String,
|
||||
)
|
||||
|
||||
|
||||
@ -108,28 +95,35 @@ def round_date_to_seconds(
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fields_inherited_from_mixin():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async def test_fields_inherited_from_mixin() -> None:
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
cat = await Category(
|
||||
name="Foo", code=123, created_by="Sam", updated_by="Max"
|
||||
).save()
|
||||
sub = await Subject(name="Bar", category=cat).save()
|
||||
mixin_columns = ["created_date", "updated_date"]
|
||||
mixin2_columns = ["created_by", "updated_by"]
|
||||
assert all(field in Category.Meta.model_fields for field in mixin_columns)
|
||||
assert all(
|
||||
field in Category.ormar_config.model_fields for field in mixin_columns
|
||||
)
|
||||
assert cat.created_date is not None
|
||||
assert cat.updated_date is not None
|
||||
assert all(field in Subject.Meta.model_fields for field in mixin_columns)
|
||||
assert all(
|
||||
field in Subject.ormar_config.model_fields for field in mixin_columns
|
||||
)
|
||||
assert sub.created_date is not None
|
||||
assert sub.updated_date is not None
|
||||
|
||||
assert all(field in Category.Meta.model_fields for field in mixin2_columns)
|
||||
assert all(
|
||||
field not in Subject.Meta.model_fields for field in mixin2_columns
|
||||
field in Category.ormar_config.model_fields for field in mixin2_columns
|
||||
)
|
||||
assert all(
|
||||
field not in Subject.ormar_config.model_fields
|
||||
for field in mixin2_columns
|
||||
)
|
||||
|
||||
inspector = sa.inspect(engine)
|
||||
inspector = sa.inspect(base_ormar_config.engine)
|
||||
assert "categories" in inspector.get_table_names()
|
||||
table_columns = [x.get("name") for x in inspector.get_columns("categories")]
|
||||
assert all(col in table_columns for col in mixin_columns + mixin2_columns)
|
||||
@ -147,6 +141,7 @@ async def test_fields_inherited_from_mixin():
|
||||
assert round_date_to_seconds(sub2.created_date) == round_date_to_seconds(
|
||||
sub.created_date
|
||||
)
|
||||
assert sub2.category is not None
|
||||
assert sub2.category.updated_date is not None
|
||||
assert round_date_to_seconds(
|
||||
sub2.category.created_date
|
||||
|
||||
@ -1,32 +1,26 @@
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
import sqlalchemy as sa
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
from pydantic import computed_field
|
||||
|
||||
metadata = sa.MetaData()
|
||||
database = databases.Database(DATABASE_URL)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class BaseFoo(ormar.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
@ormar.property_field
|
||||
@computed_field
|
||||
def prefixed_name(self) -> str:
|
||||
return "prefix_" + self.name
|
||||
|
||||
|
||||
class Foo(BaseFoo):
|
||||
class Meta:
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
@ormar.property_field
|
||||
@computed_field
|
||||
def double_prefixed_name(self) -> str:
|
||||
return "prefix2_" + self.name
|
||||
|
||||
@ -34,30 +28,22 @@ class Foo(BaseFoo):
|
||||
|
||||
|
||||
class Bar(BaseFoo):
|
||||
class Meta:
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
@ormar.property_field
|
||||
@computed_field
|
||||
def prefixed_name(self) -> str:
|
||||
return "baz_" + self.name
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_property_fields_are_inherited():
|
||||
foo = Foo(name="foo")
|
||||
assert foo.prefixed_name == "prefix_foo"
|
||||
assert foo.dict() == {
|
||||
assert foo.model_dump() == {
|
||||
"name": "foo",
|
||||
"id": None,
|
||||
"double_prefixed_name": "prefix2_foo",
|
||||
@ -66,4 +52,4 @@ def test_property_fields_are_inherited():
|
||||
|
||||
bar = Bar(name="bar")
|
||||
assert bar.prefixed_name == "baz_bar"
|
||||
assert bar.dict() == {"name": "bar", "id": None, "prefixed_name": "baz_bar"}
|
||||
assert bar.model_dump() == {"name": "bar", "id": None, "prefixed_name": "baz_bar"}
|
||||
|
||||
@ -1,25 +1,17 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL)
|
||||
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 BaseModel(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
abstract = True
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
id: uuid.UUID = ormar.UUID(
|
||||
primary_key=True, default=uuid.uuid4, uuid_format="string"
|
||||
@ -29,36 +21,29 @@ class BaseModel(ormar.Model):
|
||||
|
||||
|
||||
class Member(BaseModel):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "members"
|
||||
ormar_config = base_ormar_config.copy(tablename="members")
|
||||
|
||||
first_name: str = ormar.String(max_length=50)
|
||||
last_name: str = ormar.String(max_length=50)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_model_structure():
|
||||
assert "id" in BaseModel.__fields__
|
||||
assert "id" in BaseModel.Meta.model_fields
|
||||
assert BaseModel.Meta.model_fields["id"].has_default()
|
||||
assert BaseModel.__fields__["id"].default_factory is not None
|
||||
assert "id" in BaseModel.model_fields
|
||||
assert "id" in BaseModel.ormar_config.model_fields
|
||||
assert BaseModel.ormar_config.model_fields["id"].has_default()
|
||||
assert BaseModel.model_fields["id"].default_factory is not None
|
||||
|
||||
assert "id" in Member.__fields__
|
||||
assert "id" in Member.Meta.model_fields
|
||||
assert Member.Meta.model_fields["id"].has_default()
|
||||
assert Member.__fields__["id"].default_factory is not None
|
||||
assert "id" in Member.model_fields
|
||||
assert "id" in Member.ormar_config.model_fields
|
||||
assert Member.ormar_config.model_fields["id"].has_default()
|
||||
assert Member.model_fields["id"].default_factory is not None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fields_inherited_with_default():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Member(first_name="foo", last_name="bar").save()
|
||||
await Member.objects.create(first_name="foo", last_name="bar")
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
import datetime
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class TableBase(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
abstract = True
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
created_by: str = ormar.String(max_length=20, default="test")
|
||||
@ -27,8 +22,7 @@ class TableBase(ormar.Model):
|
||||
|
||||
|
||||
class NationBase(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
abstract = True
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
name: str = ormar.String(max_length=50)
|
||||
alpha2_code: str = ormar.String(max_length=2)
|
||||
@ -37,22 +31,15 @@ class NationBase(ormar.Model):
|
||||
|
||||
|
||||
class Nation(NationBase, TableBase):
|
||||
class Meta(ormar.ModelMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_is_not_abstract_by_default():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
sweden = await Nation(
|
||||
name="Sweden", alpha2_code="SE", region="Europe", subregion="Scandinavia"
|
||||
).save()
|
||||
|
||||
@ -1,29 +1,20 @@
|
||||
import databases
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Library(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Package(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
library: Library = ormar.ForeignKey(Library, related_name="packages")
|
||||
@ -31,8 +22,7 @@ class Package(ormar.Model):
|
||||
|
||||
|
||||
class Ticket(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
number: int = ormar.Integer()
|
||||
@ -40,8 +30,7 @@ class Ticket(ormar.Model):
|
||||
|
||||
|
||||
class TicketPackage(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
status: str = ormar.String(max_length=100)
|
||||
@ -49,11 +38,16 @@ class TicketPackage(ormar.Model):
|
||||
package: Package = ormar.ForeignKey(Package, related_name="tickets")
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_have_proper_children():
|
||||
TicketPackageOut = TicketPackage.get_pydantic(exclude={"ticket"})
|
||||
assert "package" in TicketPackageOut.__fields__
|
||||
PydanticPackage = TicketPackageOut.__fields__["package"].type_
|
||||
assert "library" in PydanticPackage.__fields__
|
||||
assert "package" in TicketPackageOut.model_fields
|
||||
PydanticPackage = TicketPackageOut.__pydantic_core_schema__["schema"]["fields"][
|
||||
"package"
|
||||
]["schema"]["schema"]["schema"]["cls"]
|
||||
assert "library" in PydanticPackage.model_fields
|
||||
|
||||
|
||||
def test_casts_properly():
|
||||
@ -69,7 +63,7 @@ def test_casts_properly():
|
||||
}
|
||||
test_package = TicketPackage(**payload)
|
||||
TicketPackageOut = TicketPackage.get_pydantic(exclude={"ticket"})
|
||||
parsed = TicketPackageOut(**test_package.dict()).dict()
|
||||
parsed = TicketPackageOut(**test_package.model_dump()).model_dump()
|
||||
assert "ticket" not in parsed
|
||||
assert "package" in parsed
|
||||
assert "library" in parsed.get("package")
|
||||
|
||||
@ -1,23 +1,13 @@
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL)
|
||||
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 NewTestModel(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
a: int = ormar.Integer(primary_key=True)
|
||||
b: str = ormar.String(max_length=1)
|
||||
@ -27,15 +17,9 @@ class NewTestModel(ormar.Model):
|
||||
f: str = ormar.String(max_length=1)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_model_field_order():
|
||||
TestCreate = NewTestModel.get_pydantic(exclude={"a"})
|
||||
assert list(TestCreate.__fields__.keys()) == ["b", "c", "d", "e", "f"]
|
||||
assert list(TestCreate.model_fields.keys()) == ["b", "c", "d", "e", "f"]
|
||||
|
||||
@ -1,28 +1,26 @@
|
||||
import enum
|
||||
|
||||
import databases
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from pydantic import ValidationError
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
from pydantic import ValidationError, field_validator
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL)
|
||||
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 BaseModel(ormar.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
ormar_config = base_ormar_config.copy(abstract=True)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
str_field: str = ormar.String(min_length=5, max_length=10, nullable=False)
|
||||
|
||||
@field_validator("str_field")
|
||||
def validate_str_field(cls, v):
|
||||
if " " not in v:
|
||||
raise ValueError("must contain a space")
|
||||
return v
|
||||
|
||||
|
||||
class EnumExample(str, enum.Enum):
|
||||
@ -32,24 +30,17 @@ class EnumExample(str, enum.Enum):
|
||||
|
||||
|
||||
class ModelExample(BaseModel):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "examples"
|
||||
ormar_config = base_ormar_config.copy(tablename="examples")
|
||||
|
||||
str_field: str = ormar.String(min_length=5, max_length=10, nullable=False)
|
||||
enum_field: str = ormar.String(
|
||||
max_length=1, nullable=False, choices=list(EnumExample)
|
||||
)
|
||||
|
||||
@pydantic.validator("str_field")
|
||||
def validate_str_field(cls, v):
|
||||
if " " not in v:
|
||||
raise ValueError("must contain a space")
|
||||
return v
|
||||
enum_field: str = ormar.Enum(enum_class=EnumExample, nullable=False)
|
||||
|
||||
|
||||
ModelExampleCreate = ModelExample.get_pydantic(exclude={"id"})
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_ormar_validator():
|
||||
ModelExample(str_field="a aaaaaa", enum_field="A")
|
||||
with pytest.raises(ValidationError) as e:
|
||||
@ -57,7 +48,7 @@ def test_ormar_validator():
|
||||
assert "must contain a space" in str(e)
|
||||
with pytest.raises(ValidationError) as e:
|
||||
ModelExample(str_field="a aaaaaaa", enum_field="Z")
|
||||
assert "not in allowed choices" in str(e)
|
||||
assert "Input should be 'A', 'B' or 'C'" in str(e)
|
||||
|
||||
|
||||
def test_pydantic_validator():
|
||||
@ -67,4 +58,4 @@ def test_pydantic_validator():
|
||||
assert "must contain a space" in str(e)
|
||||
with pytest.raises(ValidationError) as e:
|
||||
ModelExampleCreate(str_field="a aaaaaaa", enum_field="Z")
|
||||
assert "not in allowed choices" in str(e)
|
||||
assert "Input should be 'A', 'B' or 'C'" in str(e)
|
||||
|
||||
@ -1,22 +1,13 @@
|
||||
import enum
|
||||
|
||||
import databases
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from pydantic import ValidationError
|
||||
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
from pydantic import ValidationError, field_validator
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
database = databases.Database(DATABASE_URL)
|
||||
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 EnumExample(str, enum.Enum):
|
||||
@ -26,18 +17,13 @@ class EnumExample(str, enum.Enum):
|
||||
|
||||
|
||||
class ModelExample(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
database = database
|
||||
metadata = metadata
|
||||
tablename = "examples"
|
||||
ormar_config = base_ormar_config.copy(tablename="examples")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
str_field: str = ormar.String(min_length=5, max_length=10, nullable=False)
|
||||
enum_field: str = ormar.String(
|
||||
max_length=1, nullable=False, choices=list(EnumExample)
|
||||
)
|
||||
enum_field: str = ormar.Enum(nullable=False, enum_class=EnumExample)
|
||||
|
||||
@pydantic.validator("str_field")
|
||||
@field_validator("str_field")
|
||||
def validate_str_field(cls, v):
|
||||
if " " not in v:
|
||||
raise ValueError("must contain a space")
|
||||
@ -47,6 +33,9 @@ class ModelExample(ormar.Model):
|
||||
ModelExampleCreate = ModelExample.get_pydantic(exclude={"id"})
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_ormar_validator():
|
||||
ModelExample(str_field="a aaaaaa", enum_field="A")
|
||||
with pytest.raises(ValidationError) as e:
|
||||
@ -54,7 +43,7 @@ def test_ormar_validator():
|
||||
assert "must contain a space" in str(e)
|
||||
with pytest.raises(ValidationError) as e:
|
||||
ModelExample(str_field="a aaaaaaa", enum_field="Z")
|
||||
assert "not in allowed choices" in str(e)
|
||||
assert "Input should be 'A', 'B' or 'C'" in str(e)
|
||||
|
||||
|
||||
def test_pydantic_validator():
|
||||
@ -64,4 +53,4 @@ def test_pydantic_validator():
|
||||
assert "must contain a space" in str(e)
|
||||
with pytest.raises(ValidationError) as e:
|
||||
ModelExampleCreate(str_field="a aaaaaaa", enum_field="Z")
|
||||
assert "not in allowed choices" in str(e)
|
||||
assert "Input should be 'A', 'B' or 'C'" in str(e)
|
||||
|
||||
@ -1,25 +1,22 @@
|
||||
import sqlite3
|
||||
|
||||
import asyncpg # type: ignore
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar.fields.constraints
|
||||
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()
|
||||
|
||||
|
||||
class Product(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "products"
|
||||
metadata = metadata
|
||||
database = database
|
||||
constraints = [
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="products",
|
||||
constraints=[
|
||||
ormar.fields.constraints.CheckColumns("inventory > buffer"),
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -28,20 +25,14 @@ class Product(ormar.Model):
|
||||
buffer: int = ormar.Integer()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_check_columns_exclude_mysql():
|
||||
if Product.Meta.database._backend._dialect.name != "mysql":
|
||||
async with database: # pragma: no cover
|
||||
async with database.transaction(force_rollback=True):
|
||||
if Product.ormar_config.database._backend._dialect.name != "mysql":
|
||||
async with base_ormar_config.database: # pragma: no cover
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await Product.objects.create(
|
||||
name="Mars", company="Nestle", inventory=100, buffer=10
|
||||
)
|
||||
|
||||
@ -1,24 +1,20 @@
|
||||
import asyncpg # type: ignore
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar.fields.constraints
|
||||
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()
|
||||
|
||||
|
||||
class Product(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "products"
|
||||
metadata = metadata
|
||||
database = database
|
||||
constraints = [
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="products",
|
||||
constraints=[
|
||||
ormar.fields.constraints.IndexColumns("company", "name", name="my_index"),
|
||||
ormar.fields.constraints.IndexColumns("location", "company_type"),
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -27,19 +23,13 @@ class Product(ormar.Model):
|
||||
company_type: str = ormar.String(max_length=200)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_table_structure():
|
||||
assert len(Product.Meta.table.indexes) > 0
|
||||
assert len(Product.ormar_config.table.indexes) > 0
|
||||
indexes = sorted(
|
||||
list(Product.Meta.table.indexes), key=lambda x: x.name, reverse=True
|
||||
list(Product.ormar_config.table.indexes), key=lambda x: x.name, reverse=True
|
||||
)
|
||||
test_index = indexes[0]
|
||||
assert test_index.name == "my_index"
|
||||
@ -52,8 +42,8 @@ def test_table_structure():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_index_is_not_unique():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await Product.objects.create(
|
||||
name="Cookies", company="Nestle", location="A", company_type="B"
|
||||
)
|
||||
|
||||
@ -1,43 +1,34 @@
|
||||
import sqlite3
|
||||
|
||||
import asyncpg # type: ignore
|
||||
import databases
|
||||
import ormar.fields.constraints
|
||||
import pymysql
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar.fields.constraints
|
||||
from tests.settings import DATABASE_URL
|
||||
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 Product(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "products"
|
||||
metadata = metadata
|
||||
database = database
|
||||
constraints = [ormar.fields.constraints.UniqueColumns("name", "company")]
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="products",
|
||||
constraints=[ormar.fields.constraints.UniqueColumns("name", "company")],
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
company: str = ormar.String(max_length=200)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unique_columns():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await Product.objects.create(name="Cookies", company="Nestle")
|
||||
await Product.objects.create(name="Mars", company="Mars")
|
||||
await Product.objects.create(name="Mars", company="Nestle")
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import random
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
@ -16,10 +16,11 @@ def key():
|
||||
|
||||
|
||||
class Model(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "models"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = ormar.OrmarConfig(
|
||||
tablename="models",
|
||||
metadata=metadata,
|
||||
database=database,
|
||||
)
|
||||
|
||||
id: str = ormar.String(primary_key=True, default=key, max_length=8)
|
||||
name: str = ormar.String(max_length=32)
|
||||
|
||||
@ -2,13 +2,13 @@ from random import choice
|
||||
from string import ascii_uppercase
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import sqlalchemy
|
||||
from ormar import Float, String
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
from ormar import Float, String
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
@ -19,14 +19,14 @@ def get_id() -> str:
|
||||
return "".join(choice(ascii_uppercase) for _ in range(12))
|
||||
|
||||
|
||||
class MainMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = ormar.OrmarConfig(
|
||||
metadata=metadata,
|
||||
database=database,
|
||||
)
|
||||
|
||||
|
||||
class PositionOrm(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
name: str = String(primary_key=True, max_length=50)
|
||||
x: float = Float()
|
||||
@ -35,8 +35,7 @@ class PositionOrm(ormar.Model):
|
||||
|
||||
|
||||
class PositionOrmDef(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
name: str = String(primary_key=True, max_length=50, default=get_id)
|
||||
x: float = Float()
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import uuid
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
@ -13,10 +13,11 @@ db = databases.Database(DATABASE_URL)
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "user"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = ormar.OrmarConfig(
|
||||
tablename="user",
|
||||
metadata=metadata,
|
||||
database=db,
|
||||
)
|
||||
|
||||
id: uuid.UUID = ormar.UUID(
|
||||
primary_key=True, default=uuid.uuid4, uuid_format="string"
|
||||
@ -29,10 +30,11 @@ class User(ormar.Model):
|
||||
|
||||
|
||||
class Token(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "token"
|
||||
metadata = metadata
|
||||
database = db
|
||||
ormar_config = ormar.OrmarConfig(
|
||||
tablename="token",
|
||||
metadata=metadata,
|
||||
database=db,
|
||||
)
|
||||
|
||||
id = ormar.Integer(primary_key=True)
|
||||
text = ormar.String(max_length=4, unique=True)
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
from typing import List, 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()
|
||||
|
||||
|
||||
class Child(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "children"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="children")
|
||||
|
||||
id: int = ormar.Integer(name="child_id", primary_key=True)
|
||||
first_name: str = ormar.String(name="fname", max_length=100)
|
||||
@ -24,10 +19,7 @@ class Child(ormar.Model):
|
||||
|
||||
|
||||
class Artist(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "artists"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="artists")
|
||||
|
||||
id: int = ormar.Integer(name="artist_id", primary_key=True)
|
||||
first_name: str = ormar.String(name="fname", max_length=100)
|
||||
@ -37,37 +29,28 @@ class Artist(ormar.Model):
|
||||
|
||||
|
||||
class Album(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "music_albums"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="music_albums")
|
||||
|
||||
id: int = ormar.Integer(name="album_id", primary_key=True)
|
||||
name: str = ormar.String(name="album_name", max_length=100)
|
||||
artist: Optional[Artist] = ormar.ForeignKey(Artist, name="artist_id")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_table_structure():
|
||||
assert "album_id" in [x.name for x in Album.Meta.table.columns]
|
||||
assert "album_name" in [x.name for x in Album.Meta.table.columns]
|
||||
assert "fname" in [x.name for x in Artist.Meta.table.columns]
|
||||
assert "lname" in [x.name for x in Artist.Meta.table.columns]
|
||||
assert "year" in [x.name for x in Artist.Meta.table.columns]
|
||||
assert "album_id" in [x.name for x in Album.ormar_config.table.columns]
|
||||
assert "album_name" in [x.name for x in Album.ormar_config.table.columns]
|
||||
assert "fname" in [x.name for x in Artist.ormar_config.table.columns]
|
||||
assert "lname" in [x.name for x in Artist.ormar_config.table.columns]
|
||||
assert "year" in [x.name for x in Artist.ormar_config.table.columns]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_working_with_aliases():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
artist = await Artist.objects.create(
|
||||
first_name="Ted", last_name="Mosbey", born_year=1975
|
||||
)
|
||||
@ -124,7 +107,7 @@ async def test_working_with_aliases():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_bulk_operations_and_fields():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
d1 = Child(first_name="Daughter", last_name="1", born_year=1990)
|
||||
d2 = Child(first_name="Daughter", last_name="2", born_year=1991)
|
||||
await Child.objects.bulk_create([d1, d2])
|
||||
@ -155,8 +138,8 @@ async def test_bulk_operations_and_fields():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_working_with_aliases_get_or_create():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
artist, created = await Artist.objects.get_or_create(
|
||||
first_name="Teddy", last_name="Bear", born_year=2020
|
||||
)
|
||||
@ -169,7 +152,7 @@ async def test_working_with_aliases_get_or_create():
|
||||
assert artist == artist2
|
||||
assert created is False
|
||||
|
||||
art3 = artist2.dict()
|
||||
art3 = artist2.model_dump()
|
||||
art3["born_year"] = 2019
|
||||
await Artist.objects.update_or_create(**art3)
|
||||
|
||||
|
||||
@ -1,17 +1,15 @@
|
||||
import datetime
|
||||
from enum import Enum
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar import ModelDefinitionError
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config(force_rollback=True)
|
||||
|
||||
|
||||
def time():
|
||||
@ -24,10 +22,7 @@ class MyEnum(Enum):
|
||||
|
||||
|
||||
class Example(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "example"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="example")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=200, default="aaa")
|
||||
@ -41,25 +36,17 @@ class Example(ormar.Model):
|
||||
|
||||
|
||||
class EnumExample(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "enum_example"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="enum_example")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
size: MyEnum = ormar.Enum(enum_class=MyEnum, default=MyEnum.SMALL)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_proper_enum_column_type():
|
||||
assert Example.__fields__["size"].type_ == MyEnum
|
||||
assert Example.model_fields["size"].__type__ == MyEnum
|
||||
|
||||
|
||||
def test_accepts_only_proper_enums():
|
||||
@ -73,7 +60,7 @@ def test_accepts_only_proper_enums():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_enum_bulk_operations():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
examples = [EnumExample(), EnumExample()]
|
||||
await EnumExample.objects.bulk_create(examples)
|
||||
|
||||
@ -90,7 +77,7 @@ async def test_enum_bulk_operations():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_enum_filter():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
examples = [EnumExample(), EnumExample(size=MyEnum.BIG)]
|
||||
await EnumExample.objects.bulk_create(examples)
|
||||
|
||||
@ -103,7 +90,7 @@ async def test_enum_filter():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_crud():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
example = Example()
|
||||
await example.save()
|
||||
|
||||
@ -130,15 +117,12 @@ async def test_model_crud():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_invalid_enum_field():
|
||||
async with database:
|
||||
async def test_invalid_enum_field() -> None:
|
||||
async with base_ormar_config.database:
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class Example2(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "example"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="example2")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
size: MyEnum = ormar.Enum(enum_class=[])
|
||||
size: MyEnum = ormar.Enum(enum_class=[]) # type: ignore
|
||||
|
||||
@ -1,21 +1,14 @@
|
||||
import uuid
|
||||
from typing import ClassVar
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from pydantic import root_validator
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
from pydantic import model_validator
|
||||
|
||||
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 Mol(ormar.Model):
|
||||
@ -24,8 +17,7 @@ class Mol(ormar.Model):
|
||||
"12345678-abcd-1234-abcd-123456789abc"
|
||||
)
|
||||
|
||||
class Meta(BaseMeta):
|
||||
tablename = "mols"
|
||||
ormar_config = base_ormar_config.copy(tablename="mols")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, index=True, uuid_format="hex")
|
||||
smiles: str = ormar.String(nullable=False, unique=True, max_length=256)
|
||||
@ -36,7 +28,7 @@ class Mol(ormar.Model):
|
||||
kwargs["id"] = self._UUID_NAMESPACE
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@root_validator()
|
||||
@model_validator(mode="before")
|
||||
def make_canonical_smiles_and_uuid(cls, values):
|
||||
values["id"], values["smiles"] = cls.uuid(values["smiles"])
|
||||
return values
|
||||
@ -47,17 +39,12 @@ class Mol(ormar.Model):
|
||||
return id_, smiles
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_json_column():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Mol.objects.create(smiles="Cc1ccccc1")
|
||||
count = await Mol.objects.count()
|
||||
assert count == 1
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
from datetime import timezone, timedelta, datetime, date, time
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from datetime import date, datetime, time, timedelta, timezone
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
|
||||
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 DateFieldsModel(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
created_date: datetime = ormar.DateTime(
|
||||
@ -29,27 +24,21 @@ class DateFieldsModel(ormar.Model):
|
||||
|
||||
|
||||
class SampleModel(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
updated_at: datetime = ormar.DateTime()
|
||||
|
||||
|
||||
class TimeModel(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
elapsed: time = ormar.Time()
|
||||
|
||||
|
||||
class DateModel(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
creation_date: date = ormar.Date()
|
||||
@ -59,24 +48,15 @@ class MyModel(ormar.Model):
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
created_at: datetime = ormar.DateTime(timezone=True, nullable=False)
|
||||
|
||||
class Meta:
|
||||
tablename = "mymodels"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="mymodels")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_crud_with_timezone():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
datemodel = await DateFieldsModel().save()
|
||||
assert datemodel.created_date is not None
|
||||
assert datemodel.updated_date is not None
|
||||
@ -84,7 +64,7 @@ async def test_model_crud_with_timezone():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_query_with_datetime_in_filter():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
creation_dt = datetime(2021, 5, 18, 0, 0, 0, 0)
|
||||
sample = await SampleModel.objects.create(updated_at=creation_dt)
|
||||
|
||||
@ -98,7 +78,7 @@ async def test_query_with_datetime_in_filter():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_query_with_date_in_filter():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
sample = await TimeModel.objects.create(elapsed=time(0, 20, 20))
|
||||
await TimeModel.objects.create(elapsed=time(0, 12, 0))
|
||||
await TimeModel.objects.create(elapsed=time(0, 19, 55))
|
||||
@ -114,7 +94,7 @@ async def test_query_with_date_in_filter():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_query_with_time_in_filter():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await DateModel.objects.create(creation_date=date(2021, 5, 18))
|
||||
sample2 = await DateModel.objects.create(creation_date=date(2021, 5, 19))
|
||||
sample3 = await DateModel.objects.create(creation_date=date(2021, 5, 20))
|
||||
@ -130,7 +110,7 @@ async def test_query_with_time_in_filter():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_filtering_by_timezone_with_timedelta():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
now_utc = datetime.now(timezone.utc)
|
||||
object = MyModel(created_at=now_utc)
|
||||
await object.save()
|
||||
|
||||
@ -1,38 +1,26 @@
|
||||
# type: ignore
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar import ModelDefinitionError, property_field
|
||||
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()
|
||||
|
||||
|
||||
class Song(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "songs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="songs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_equality():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
song1 = await Song.objects.create(name="Song")
|
||||
song2 = await Song.objects.create(name="Song")
|
||||
song3 = Song(name="Song")
|
||||
@ -49,7 +37,7 @@ async def test_equality():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hash_doesnt_change_with_fields_if_pk():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
song1 = await Song.objects.create(name="Song")
|
||||
prev_hash = hash(song1)
|
||||
|
||||
@ -59,7 +47,7 @@ async def test_hash_doesnt_change_with_fields_if_pk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hash_changes_with_fields_if_no_pk():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
song1 = Song(name="Song")
|
||||
prev_hash = hash(song1)
|
||||
|
||||
|
||||
@ -1,26 +1,26 @@
|
||||
import databases
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar import Extra
|
||||
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
|
||||
|
||||
base_ormar_config = create_config(force_rollback=True)
|
||||
|
||||
|
||||
class Child(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "children"
|
||||
metadata = metadata
|
||||
database = database
|
||||
extra = Extra.ignore
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="children",
|
||||
extra=Extra.ignore,
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(name="child_id", primary_key=True)
|
||||
first_name: str = ormar.String(name="fname", max_length=100)
|
||||
last_name: str = ormar.String(name="lname", max_length=100)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_allow_extra_parameter():
|
||||
child = Child(first_name="Test", last_name="Name", extra_param="Unexpected")
|
||||
assert child.first_name == "Test"
|
||||
|
||||
@ -1,57 +1,43 @@
|
||||
import asyncio
|
||||
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(force_rollback=True)
|
||||
|
||||
|
||||
class SchoolClass(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "app.schoolclasses"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="app.schoolclasses")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "app.categories"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="app.categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Student(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "app.students"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="app.students")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
gpa: float = ormar.Float()
|
||||
schoolclass: Optional[SchoolClass] = ormar.ForeignKey(SchoolClass, related_name="students")
|
||||
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True, related_name="students")
|
||||
schoolclass: Optional[SchoolClass] = ormar.ForeignKey(
|
||||
SchoolClass, related_name="students"
|
||||
)
|
||||
category: Optional[Category] = ormar.ForeignKey(
|
||||
Category, nullable=True, related_name="students"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
async def create_data():
|
||||
@ -59,27 +45,37 @@ async def create_data():
|
||||
class2 = await SchoolClass.objects.create(name="Logic")
|
||||
category = await Category.objects.create(name="Foreign")
|
||||
category2 = await Category.objects.create(name="Domestic")
|
||||
await Student.objects.create(name="Jane", category=category, schoolclass=class1, gpa=3.2)
|
||||
await Student.objects.create(name="Judy", category=category2, schoolclass=class1, gpa=2.6)
|
||||
await Student.objects.create(name="Jack", category=category2, schoolclass=class2, gpa=3.8)
|
||||
await Student.objects.create(
|
||||
name="Jane", category=category, schoolclass=class1, gpa=3.2
|
||||
)
|
||||
await Student.objects.create(
|
||||
name="Judy", category=category2, schoolclass=class1, gpa=2.6
|
||||
)
|
||||
await Student.objects.create(
|
||||
name="Jack", category=category2, schoolclass=class2, gpa=3.8
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_quotes_left_join():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await create_data()
|
||||
students = await Student.objects.filter(
|
||||
(Student.schoolclass.name == "Math") | (Student.category.name == "Foreign")
|
||||
(Student.schoolclass.name == "Math")
|
||||
| (Student.category.name == "Foreign")
|
||||
).all()
|
||||
for student in students:
|
||||
assert student.schoolclass.name == "Math" or student.category.name == "Foreign"
|
||||
assert (
|
||||
student.schoolclass.name == "Math"
|
||||
or student.category.name == "Foreign"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_quotes_reverse_join():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await create_data()
|
||||
schoolclasses = await SchoolClass.objects.filter(students__gpa__gt=3).all()
|
||||
for schoolclass in schoolclasses:
|
||||
@ -89,11 +85,12 @@ async def test_quotes_reverse_join():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_quotes_deep_join():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await create_data()
|
||||
schoolclasses = await SchoolClass.objects.filter(students__category__name="Domestic").all()
|
||||
schoolclasses = await SchoolClass.objects.filter(
|
||||
students__category__name="Domestic"
|
||||
).all()
|
||||
for schoolclass in schoolclasses:
|
||||
for student in schoolclass.students:
|
||||
assert student.category.name == "Domestic"
|
||||
|
||||
|
||||
@ -1,31 +1,22 @@
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
from ormar import BaseField
|
||||
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):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class PriceList(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "price_lists"
|
||||
ormar_config = base_ormar_config.copy(tablename="price_lists")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Category(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "categories"
|
||||
ormar_config = base_ormar_config.copy(tablename="categories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -33,8 +24,7 @@ class Category(ormar.Model):
|
||||
|
||||
|
||||
class Product(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "product"
|
||||
ormar_config = base_ormar_config.copy(tablename="product")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -42,19 +32,13 @@ class Product(ormar.Model):
|
||||
category = ormar.ForeignKey(Category)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_fields_access():
|
||||
# basic access
|
||||
assert Product.id._field == Product.Meta.model_fields["id"]
|
||||
assert Product.id.id == Product.Meta.model_fields["id"]
|
||||
assert Product.id._field == Product.ormar_config.model_fields["id"]
|
||||
assert Product.id.id == Product.ormar_config.model_fields["id"]
|
||||
assert Product.pk.id == Product.id.id
|
||||
assert isinstance(Product.id._field, BaseField)
|
||||
assert Product.id._access_chain == "id"
|
||||
@ -62,19 +46,19 @@ def test_fields_access():
|
||||
|
||||
# nested models
|
||||
curr_field = Product.category.name
|
||||
assert curr_field._field == Category.Meta.model_fields["name"]
|
||||
assert curr_field._field == Category.ormar_config.model_fields["name"]
|
||||
assert curr_field._access_chain == "category__name"
|
||||
assert curr_field._source_model == Product
|
||||
|
||||
# deeper nesting
|
||||
curr_field = Product.category.price_lists.name
|
||||
assert curr_field._field == PriceList.Meta.model_fields["name"]
|
||||
assert curr_field._field == PriceList.ormar_config.model_fields["name"]
|
||||
assert curr_field._access_chain == "category__price_lists__name"
|
||||
assert curr_field._source_model == Product
|
||||
|
||||
# reverse nesting
|
||||
curr_field = PriceList.categories.products.rating
|
||||
assert curr_field._field == Product.Meta.model_fields["rating"]
|
||||
assert curr_field._field == Product.ormar_config.model_fields["rating"]
|
||||
assert curr_field._access_chain == "categories__products__rating"
|
||||
assert curr_field._source_model == PriceList
|
||||
|
||||
@ -191,8 +175,8 @@ def test_combining_groups_together():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_filtering_by_field_access():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
category = await Category(name="Toys").save()
|
||||
product2 = await Product(
|
||||
name="My Little Pony", rating=3.8, category=category
|
||||
|
||||
@ -1,25 +1,17 @@
|
||||
import uuid
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from typing import Optional
|
||||
|
||||
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
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class PageLink(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "pagelinks"
|
||||
ormar_config = base_ormar_config.copy(tablename="pagelinks")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
value: str = ormar.String(max_length=2048)
|
||||
@ -27,8 +19,7 @@ class PageLink(ormar.Model):
|
||||
|
||||
|
||||
class Post(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "posts"
|
||||
ormar_config = base_ormar_config.copy(tablename="posts")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
title: str = ormar.String(max_length=500)
|
||||
@ -38,16 +29,14 @@ class Post(ormar.Model):
|
||||
|
||||
|
||||
class Department(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4())
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Course(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -55,18 +44,13 @@ class Course(ormar.Model):
|
||||
department: Optional[Department] = ormar.ForeignKey(Department)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pass_int_values_as_fk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
link = await PageLink(id=1, value="test", country="USA").save()
|
||||
await Post.objects.create(title="My post", link=link.id)
|
||||
post_check = await Post.objects.select_related("link").get()
|
||||
@ -75,7 +59,7 @@ async def test_pass_int_values_as_fk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pass_uuid_value_as_fk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
dept = await Department(name="Department test").save()
|
||||
await Course(name="Test course", department=dept.id).save()
|
||||
|
||||
@ -1,31 +1,24 @@
|
||||
import uuid
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
from ormar.exceptions import QueryDefinitionError
|
||||
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
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "users3"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="users3")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, default="")
|
||||
|
||||
|
||||
class User2(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "users4"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="users4")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(
|
||||
uuid_format="string", primary_key=True, default=uuid.uuid4
|
||||
@ -34,10 +27,7 @@ class User2(ormar.Model):
|
||||
|
||||
|
||||
class Task(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "tasks"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="tasks")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, default="")
|
||||
@ -45,10 +35,7 @@ class Task(ormar.Model):
|
||||
|
||||
|
||||
class Task2(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "tasks2"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="tasks2")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(
|
||||
uuid_format="string", primary_key=True, default=uuid.uuid4
|
||||
@ -57,27 +44,21 @@ class Task2(ormar.Model):
|
||||
user: User2 = ormar.ForeignKey(to=User2)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_result():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
async for user in User.objects.iterate():
|
||||
pass # pragma: no cover
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User.objects.create(name="Tom")
|
||||
jane = await User.objects.create(name="Jane")
|
||||
lucy = await User.objects.create(name="Lucy")
|
||||
@ -88,8 +69,8 @@ async def test_model_iterator():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_filter():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User.objects.create(name="Tom")
|
||||
await User.objects.create(name="Jane")
|
||||
await User.objects.create(name="Lucy")
|
||||
@ -100,8 +81,8 @@ async def test_model_iterator_filter():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_relations():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User.objects.create(name="Tom")
|
||||
jane = await User.objects.create(name="Jane")
|
||||
lucy = await User.objects.create(name="Lucy")
|
||||
@ -120,8 +101,8 @@ async def test_model_iterator_relations():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_relations_queryset_proxy():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User.objects.create(name="Tom")
|
||||
jane = await User.objects.create(name="Jane")
|
||||
|
||||
@ -146,8 +127,8 @@ async def test_model_iterator_relations_queryset_proxy():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_uneven_number_of_relations():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User.objects.create(name="Tom")
|
||||
jane = await User.objects.create(name="Jane")
|
||||
lucy = await User.objects.create(name="Lucy")
|
||||
@ -168,8 +149,8 @@ async def test_model_iterator_uneven_number_of_relations():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_uuid_pk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User2.objects.create(name="Tom")
|
||||
jane = await User2.objects.create(name="Jane")
|
||||
lucy = await User2.objects.create(name="Lucy")
|
||||
@ -180,8 +161,8 @@ async def test_model_iterator_uuid_pk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_filter_uuid_pk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User2.objects.create(name="Tom")
|
||||
await User2.objects.create(name="Jane")
|
||||
await User2.objects.create(name="Lucy")
|
||||
@ -192,8 +173,8 @@ async def test_model_iterator_filter_uuid_pk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_relations_uuid_pk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User2.objects.create(name="Tom")
|
||||
jane = await User2.objects.create(name="Jane")
|
||||
lucy = await User2.objects.create(name="Lucy")
|
||||
@ -212,8 +193,8 @@ async def test_model_iterator_relations_uuid_pk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_relations_queryset_proxy_uuid_pk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User2.objects.create(name="Tom")
|
||||
jane = await User2.objects.create(name="Jane")
|
||||
|
||||
@ -238,8 +219,8 @@ async def test_model_iterator_relations_queryset_proxy_uuid_pk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_uneven_number_of_relations_uuid_pk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User2.objects.create(name="Tom")
|
||||
jane = await User2.objects.create(name="Jane")
|
||||
lucy = await User2.objects.create(name="Lucy")
|
||||
@ -262,7 +243,7 @@ async def test_model_iterator_uneven_number_of_relations_uuid_pk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_iterator_with_prefetch_raises_error():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
with pytest.raises(QueryDefinitionError):
|
||||
async for user in User.objects.prefetch_related(User.tasks).iterate():
|
||||
pass # pragma: no cover
|
||||
|
||||
@ -1,38 +1,27 @@
|
||||
from typing import List
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class NickNames(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "nicks"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
|
||||
|
||||
class NicksHq(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "nicks_x_hq"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks_x_hq")
|
||||
|
||||
|
||||
class HQ(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "hqs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="hqs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -40,10 +29,7 @@ class HQ(ormar.Model):
|
||||
|
||||
|
||||
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, name="company_name")
|
||||
@ -51,47 +37,47 @@ class Company(ormar.Model):
|
||||
hq: HQ = ormar.ForeignKey(HQ)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_construct_with_empty_relation():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await HQ.objects.create(name="Main")
|
||||
comp = Company(name="Banzai", hq=None, founded=1988)
|
||||
comp2 = Company.construct(**dict(name="Banzai", hq=None, founded=1988))
|
||||
assert comp.dict() == comp2.dict()
|
||||
comp2 = Company.model_construct(
|
||||
**dict(name="Banzai", hq=None, founded=1988)
|
||||
)
|
||||
assert comp.model_dump() == comp2.model_dump()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_and_construct_has_same_effect():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
comp = Company(name="Banzai", hq=hq, founded=1988)
|
||||
comp2 = Company.construct(**dict(name="Banzai", hq=hq, founded=1988))
|
||||
assert comp.dict() == comp2.dict()
|
||||
comp2 = Company.model_construct(**dict(name="Banzai", hq=hq, founded=1988))
|
||||
assert comp.model_dump() == comp2.model_dump()
|
||||
|
||||
comp3 = Company.construct(**dict(name="Banzai", hq=hq.dict(), founded=1988))
|
||||
assert comp.dict() == comp3.dict()
|
||||
comp3 = Company.model_construct(
|
||||
**dict(name="Banzai", hq=hq.model_dump(), founded=1988)
|
||||
)
|
||||
assert comp.model_dump() == comp3.model_dump()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_and_construct_has_same_effect_with_m2m():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
n1 = await NickNames(name="test").save()
|
||||
n2 = await NickNames(name="test2").save()
|
||||
hq = HQ(name="Main", nicks=[n1, n2])
|
||||
hq2 = HQ.construct(**dict(name="Main", nicks=[n1, n2]))
|
||||
assert hq.dict() == hq2.dict()
|
||||
hq2 = HQ.model_construct(**dict(name="Main", nicks=[n1, n2]))
|
||||
assert hq.model_dump() == hq2.model_dump()
|
||||
|
||||
hq3 = HQ.construct(**dict(name="Main", nicks=[n1.dict(), n2.dict()]))
|
||||
assert hq.dict() == hq3.dict()
|
||||
hq3 = HQ.model_construct(
|
||||
**dict(name="Main", nicks=[n1.model_dump(), n2.model_dump()])
|
||||
)
|
||||
assert hq.model_dump() == hq3.model_dump()
|
||||
|
||||
@ -1,30 +1,23 @@
|
||||
# type: ignore
|
||||
import asyncio
|
||||
import datetime
|
||||
import decimal
|
||||
|
||||
import databases
|
||||
import pydantic
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import sqlalchemy
|
||||
import typing
|
||||
|
||||
import ormar
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from ormar.exceptions import ModelDefinitionError
|
||||
from ormar.models import Model
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class ExampleModel(Model):
|
||||
class Meta:
|
||||
tablename = "example"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="example")
|
||||
|
||||
test: int = ormar.Integer(primary_key=True)
|
||||
test_string: str = ormar.String(max_length=250)
|
||||
@ -55,21 +48,13 @@ fields_to_check = [
|
||||
|
||||
|
||||
class ExampleModel2(Model):
|
||||
class Meta:
|
||||
tablename = "examples"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="example2")
|
||||
|
||||
test: int = ormar.Integer(primary_key=True)
|
||||
test_string: str = ormar.String(max_length=250)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@ -84,7 +69,7 @@ def example():
|
||||
|
||||
|
||||
def test_not_nullable_field_is_required():
|
||||
with pytest.raises(pydantic.error_wrappers.ValidationError):
|
||||
with pytest.raises(pydantic.ValidationError):
|
||||
ExampleModel(test=1, test_string="test")
|
||||
|
||||
|
||||
@ -116,9 +101,10 @@ def test_missing_metadata():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class JsonSample2(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "jsons2"
|
||||
database = database
|
||||
ormar_config = ormar.OrmarConfig(
|
||||
tablename="jsons2",
|
||||
database=base_ormar_config.database,
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
test_json = ormar.JSON(nullable=True)
|
||||
@ -128,8 +114,18 @@ def test_missing_database():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class JsonSample3(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "jsons3"
|
||||
ormar_config = ormar.OrmarConfig(tablename="jsons3")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
test_json = ormar.JSON(nullable=True)
|
||||
|
||||
|
||||
def test_wrong_pydantic_config():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class ErrorSample(ormar.Model):
|
||||
model_config = ["test"]
|
||||
ormar_config = ormar.OrmarConfig(tablename="jsons3")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
test_json = ormar.JSON(nullable=True)
|
||||
@ -150,13 +146,15 @@ def test_primary_key_access_and_setting(example):
|
||||
|
||||
def test_pydantic_model_is_created(example):
|
||||
assert issubclass(example.__class__, pydantic.BaseModel)
|
||||
assert all([field in example.__fields__ for field in fields_to_check])
|
||||
assert all([field in example.model_fields for field in fields_to_check])
|
||||
assert example.test == 1
|
||||
|
||||
|
||||
def test_sqlalchemy_table_is_created(example):
|
||||
assert issubclass(example.Meta.table.__class__, sqlalchemy.Table)
|
||||
assert all([field in example.Meta.table.columns for field in fields_to_check])
|
||||
assert issubclass(example.ormar_config.table.__class__, sqlalchemy.Table)
|
||||
assert all(
|
||||
[field in example.ormar_config.table.columns for field in fields_to_check]
|
||||
)
|
||||
|
||||
|
||||
@typing.no_type_check
|
||||
@ -164,10 +162,7 @@ def test_no_pk_in_model_definition():
|
||||
with pytest.raises(ModelDefinitionError): # type: ignore
|
||||
|
||||
class ExampleModel2(Model): # type: ignore
|
||||
class Meta:
|
||||
tablename = "example2"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="example2")
|
||||
|
||||
test_string: str = ormar.String(max_length=250) # type: ignore
|
||||
|
||||
@ -178,37 +173,18 @@ def test_two_pks_in_model_definition():
|
||||
|
||||
@typing.no_type_check
|
||||
class ExampleModel2(Model):
|
||||
class Meta:
|
||||
tablename = "example3"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="example3")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
test_string: str = ormar.String(max_length=250, primary_key=True)
|
||||
|
||||
|
||||
@typing.no_type_check
|
||||
def test_setting_pk_column_as_pydantic_only_in_model_definition():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class ExampleModel2(Model):
|
||||
class Meta:
|
||||
tablename = "example4"
|
||||
database = database
|
||||
metadata = metadata
|
||||
|
||||
test: int = ormar.Integer(primary_key=True, pydantic_only=True)
|
||||
|
||||
|
||||
@typing.no_type_check
|
||||
def test_decimal_error_in_model_definition():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class ExampleModel2(Model):
|
||||
class Meta:
|
||||
tablename = "example5"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="example5")
|
||||
|
||||
test: decimal.Decimal = ormar.Decimal(primary_key=True)
|
||||
|
||||
@ -218,10 +194,7 @@ def test_binary_error_without_length_model_definition():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class ExampleModel2(Model):
|
||||
class Meta:
|
||||
tablename = "example6"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="example6")
|
||||
|
||||
test: bytes = ormar.LargeBinary(primary_key=True, max_length=-1)
|
||||
|
||||
@ -231,10 +204,7 @@ def test_string_error_in_model_definition():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class ExampleModel2(Model):
|
||||
class Meta:
|
||||
tablename = "example6"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="example6")
|
||||
|
||||
test: str = ormar.String(primary_key=True, max_length=0)
|
||||
|
||||
|
||||
@ -3,26 +3,22 @@ import base64
|
||||
import datetime
|
||||
import os
|
||||
import uuid
|
||||
from typing import List
|
||||
from enum import Enum
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pydantic
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar.exceptions import ModelError, NoMatch, QueryDefinitionError
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class JsonSample(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "jsons"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="jsons")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
test_json = ormar.JSON(nullable=True)
|
||||
@ -33,13 +29,10 @@ blob2 = b"test2icac89uc98"
|
||||
|
||||
|
||||
class LargeBinarySample(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "my_bolbs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="my_bolbs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
test_binary: bytes = ormar.LargeBinary(max_length=100000, choices=[blob, blob2])
|
||||
test_binary: bytes = ormar.LargeBinary(max_length=100000)
|
||||
|
||||
|
||||
blob3 = os.urandom(64)
|
||||
@ -47,47 +40,34 @@ blob4 = os.urandom(100)
|
||||
|
||||
|
||||
class LargeBinaryStr(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "my_str_blobs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="my_str_bolbs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
test_binary: str = ormar.LargeBinary(
|
||||
max_length=100000, choices=[blob3, blob4], represent_as_base64_str=True
|
||||
max_length=100000, represent_as_base64_str=True
|
||||
)
|
||||
|
||||
|
||||
class LargeBinaryNullableStr(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "my_str_blobs2"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="my_str_bolbs2")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
test_binary: str = ormar.LargeBinary(
|
||||
max_length=100000,
|
||||
choices=[blob3, blob4],
|
||||
represent_as_base64_str=True,
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
|
||||
class UUIDSample(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "uuids"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="uuids")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4)
|
||||
test_text: str = ormar.Text()
|
||||
|
||||
|
||||
class UUIDSample2(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "uuids2"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="uuids2")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(
|
||||
primary_key=True, default=uuid.uuid4, uuid_format="string"
|
||||
@ -96,95 +76,78 @@ class UUIDSample2(ormar.Model):
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "users"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="users")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, default="")
|
||||
|
||||
|
||||
class User2(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "users2"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="users2")
|
||||
|
||||
id: str = ormar.String(primary_key=True, max_length=100)
|
||||
name: str = ormar.String(max_length=100, default="")
|
||||
|
||||
|
||||
class Product(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "product"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="product")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
rating: int = ormar.Integer(minimum=1, maximum=5)
|
||||
in_stock: bool = ormar.Boolean(default=False)
|
||||
last_delivery: datetime.date = ormar.Date(default=datetime.datetime.now)
|
||||
last_delivery: datetime.date = ormar.Date(default=datetime.date.today)
|
||||
|
||||
|
||||
country_name_choices = ("Canada", "Algeria", "United States", "Belize")
|
||||
country_taxed_choices = (True,)
|
||||
country_country_code_choices = (-10, 1, 213, 1200)
|
||||
class CountryNameEnum(Enum):
|
||||
CANADA = "Canada"
|
||||
ALGERIA = "Algeria"
|
||||
USA = "United States"
|
||||
BELIZE = "Belize"
|
||||
|
||||
|
||||
class CountryCodeEnum(int, Enum):
|
||||
MINUS_TEN = -10
|
||||
ONE = 1
|
||||
TWO_HUNDRED_THIRTEEN = 213
|
||||
THOUSAND_TWO_HUNDRED = 1200
|
||||
|
||||
|
||||
class Country(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "country"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="country")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(
|
||||
max_length=9, choices=country_name_choices, default="Canada"
|
||||
)
|
||||
taxed: bool = ormar.Boolean(choices=country_taxed_choices, default=True)
|
||||
country_code: int = ormar.Integer(
|
||||
minimum=0, maximum=1000, choices=country_country_code_choices, default=1
|
||||
)
|
||||
name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, default="Canada")
|
||||
taxed: bool = ormar.Boolean(default=True)
|
||||
country_code: int = ormar.Enum(enum_class=CountryCodeEnum, default=1)
|
||||
|
||||
|
||||
class NullableCountry(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "country2"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="country2")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=9, choices=country_name_choices, nullable=True)
|
||||
name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, nullable=True)
|
||||
|
||||
|
||||
class NotNullableCountry(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "country3"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="country3")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=9, choices=country_name_choices, nullable=False)
|
||||
name: CountryNameEnum = ormar.Enum(enum_class=CountryNameEnum, nullable=False)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_model_class():
|
||||
assert list(User.Meta.model_fields.keys()) == ["id", "name"]
|
||||
assert issubclass(User.Meta.model_fields["id"].__class__, pydantic.fields.FieldInfo)
|
||||
assert User.Meta.model_fields["id"].primary_key is True
|
||||
assert isinstance(User.Meta.model_fields["name"], pydantic.fields.FieldInfo)
|
||||
assert User.Meta.model_fields["name"].max_length == 100
|
||||
assert isinstance(User.Meta.table, sqlalchemy.Table)
|
||||
assert list(User.ormar_config.model_fields.keys()) == ["id", "name"]
|
||||
assert issubclass(
|
||||
User.ormar_config.model_fields["id"].__class__, pydantic.fields.FieldInfo
|
||||
)
|
||||
assert User.ormar_config.model_fields["id"].primary_key is True
|
||||
assert isinstance(User.ormar_config.model_fields["name"], pydantic.fields.FieldInfo)
|
||||
assert User.ormar_config.model_fields["name"].max_length == 100
|
||||
assert isinstance(User.ormar_config.table, sqlalchemy.Table)
|
||||
|
||||
|
||||
def test_wrong_field_name():
|
||||
@ -200,8 +163,8 @@ def test_model_pk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_json_column():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await JsonSample.objects.create(test_json=dict(aa=12))
|
||||
await JsonSample.objects.create(test_json='{"aa": 12}')
|
||||
|
||||
@ -216,8 +179,8 @@ async def test_json_column():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_binary_column():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await LargeBinarySample.objects.create(test_binary=blob)
|
||||
await LargeBinarySample.objects.create(test_binary=blob2)
|
||||
|
||||
@ -232,8 +195,8 @@ async def test_binary_column():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_binary_str_column():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await LargeBinaryStr(test_binary=blob3).save()
|
||||
await LargeBinaryStr.objects.create(test_binary=blob4)
|
||||
|
||||
@ -248,8 +211,8 @@ async def test_binary_str_column():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_binary_nullable_str_column():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await LargeBinaryNullableStr().save()
|
||||
await LargeBinaryNullableStr.objects.create()
|
||||
items = await LargeBinaryNullableStr.objects.all()
|
||||
@ -279,8 +242,8 @@ async def test_binary_nullable_str_column():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uuid_column():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
u1 = await UUIDSample.objects.create(test_text="aa")
|
||||
u2 = await UUIDSample.objects.create(test_text="bb")
|
||||
|
||||
@ -303,7 +266,7 @@ async def test_uuid_column():
|
||||
assert item2.id == item3.id
|
||||
assert isinstance(item3.id, uuid.UUID)
|
||||
|
||||
u3 = await UUIDSample2(**u1.dict()).save()
|
||||
u3 = await UUIDSample2(**u1.model_dump()).save()
|
||||
|
||||
u1_2 = await UUIDSample.objects.get(pk=u3.id)
|
||||
assert u1_2 == u1
|
||||
@ -314,8 +277,8 @@ async def test_uuid_column():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_crud():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
users = await User.objects.all()
|
||||
assert users == []
|
||||
|
||||
@ -341,8 +304,8 @@ async def test_model_crud():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_get():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
with pytest.raises(ormar.NoMatch):
|
||||
await User.objects.get()
|
||||
|
||||
@ -366,8 +329,8 @@ async def test_model_get():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_filter():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await User.objects.create(name="Tom")
|
||||
await User.objects.create(name="Jane")
|
||||
await User.objects.create(name="Lucy")
|
||||
@ -422,7 +385,7 @@ async def test_model_filter():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wrong_query_contains_model():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
with pytest.raises(QueryDefinitionError):
|
||||
product = Product(name="90%-Cotton", rating=2)
|
||||
await Product.objects.filter(name__contains=product).count()
|
||||
@ -430,8 +393,8 @@ async def test_wrong_query_contains_model():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_exists():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await User.objects.create(name="Tom")
|
||||
assert await User.objects.filter(name="Tom").exists() is True
|
||||
assert await User.objects.filter(name="Jane").exists() is False
|
||||
@ -439,8 +402,8 @@ async def test_model_exists():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_count():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await User.objects.create(name="Tom")
|
||||
await User.objects.create(name="Jane")
|
||||
await User.objects.create(name="Lucy")
|
||||
@ -451,8 +414,8 @@ async def test_model_count():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_limit():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await User.objects.create(name="Tom")
|
||||
await User.objects.create(name="Jane")
|
||||
await User.objects.create(name="Lucy")
|
||||
@ -462,8 +425,8 @@ async def test_model_limit():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_limit_with_filter():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await User.objects.create(name="Tom")
|
||||
await User.objects.create(name="Tom")
|
||||
await User.objects.create(name="Tom")
|
||||
@ -475,8 +438,8 @@ async def test_model_limit_with_filter():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_offset():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await User.objects.create(name="Tom")
|
||||
await User.objects.create(name="Jane")
|
||||
|
||||
@ -486,8 +449,8 @@ async def test_offset():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_first():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
tom = await User.objects.create(name="Tom")
|
||||
jane = await User.objects.create(name="Jane")
|
||||
|
||||
@ -500,27 +463,11 @@ async def test_model_first():
|
||||
assert await User.objects.order_by("name").first() == jane
|
||||
|
||||
|
||||
def not_contains(a, b):
|
||||
return a not in b
|
||||
|
||||
|
||||
def contains(a, b):
|
||||
return a in b
|
||||
|
||||
|
||||
def check_choices(values: tuple, ops: List):
|
||||
ops_dict = {"in": contains, "out": not_contains}
|
||||
checks = (country_name_choices, country_taxed_choices, country_country_code_choices)
|
||||
assert all(
|
||||
[ops_dict[op](value, check) for value, op, check in zip(values, ops, checks)]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_choices():
|
||||
"""Test that choices work properly for various types of fields."""
|
||||
async with database:
|
||||
# Test valid choices.
|
||||
"""Test that enum work properly for various types of fields."""
|
||||
async with base_ormar_config.database:
|
||||
# Test valid enums values.
|
||||
await asyncio.gather(
|
||||
Country.objects.create(name="Canada", taxed=True, country_code=1),
|
||||
Country.objects.create(name="Algeria", taxed=True, country_code=213),
|
||||
@ -529,54 +476,12 @@ async def test_model_choices():
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = "Saudi Arabia", True, 1
|
||||
check_choices((name, taxed, country_code), ["out", "in", "in"])
|
||||
await Country.objects.create(
|
||||
name=name, taxed=taxed, country_code=country_code
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = "Algeria", False, 1
|
||||
check_choices((name, taxed, country_code), ["in", "out", "in"])
|
||||
await Country.objects.create(
|
||||
name=name, taxed=taxed, country_code=country_code
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = "Algeria", True, 967
|
||||
check_choices((name, taxed, country_code), ["in", "in", "out"])
|
||||
await Country.objects.create(
|
||||
name=name, taxed=taxed, country_code=country_code
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = (
|
||||
"United States",
|
||||
True,
|
||||
1,
|
||||
) # name is too long but is a valid choice
|
||||
check_choices((name, taxed, country_code), ["in", "in", "in"])
|
||||
await Country.objects.create(
|
||||
name=name, taxed=taxed, country_code=country_code
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = (
|
||||
"Algeria",
|
||||
True,
|
||||
-10,
|
||||
) # country code is too small but is a valid choice
|
||||
check_choices((name, taxed, country_code), ["in", "in", "in"])
|
||||
await Country.objects.create(
|
||||
name=name, taxed=taxed, country_code=country_code
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = (
|
||||
"Algeria",
|
||||
True,
|
||||
1200,
|
||||
) # country code is too large but is a valid choice
|
||||
check_choices((name, taxed, country_code), ["in", "in", "in"])
|
||||
await Country.objects.create(
|
||||
name=name, taxed=taxed, country_code=country_code
|
||||
)
|
||||
@ -584,34 +489,24 @@ async def test_model_choices():
|
||||
# test setting after init also triggers validation
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = "Algeria", True, 967
|
||||
check_choices((name, taxed, country_code), ["in", "in", "out"])
|
||||
country = Country()
|
||||
country.country_code = country_code
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = "Saudi Arabia", True, 1
|
||||
check_choices((name, taxed, country_code), ["out", "in", "in"])
|
||||
country = Country()
|
||||
country.name = name
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = "Algeria", False, 1
|
||||
check_choices((name, taxed, country_code), ["in", "out", "in"])
|
||||
country = Country()
|
||||
country.taxed = taxed
|
||||
|
||||
# check also update from queryset
|
||||
with pytest.raises(ValueError):
|
||||
name, taxed, country_code = "Algeria", False, 1
|
||||
check_choices((name, taxed, country_code), ["in", "out", "in"])
|
||||
await Country(name="Belize").save()
|
||||
await Country.objects.filter(name="Belize").update(name="Vietnam")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_nullable_field_model_choices():
|
||||
"""Test that choices work properly for according to nullable setting"""
|
||||
async with database:
|
||||
async def test_nullable_field_model_enum():
|
||||
"""Test that enum work properly for according to nullable setting"""
|
||||
async with base_ormar_config.database:
|
||||
c1 = await NullableCountry(name=None).save()
|
||||
assert c1.name is None
|
||||
|
||||
@ -621,8 +516,8 @@ async def test_nullable_field_model_choices():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_and_end_filters():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await User.objects.create(name="Markos Uj")
|
||||
await User.objects.create(name="Maqua Bigo")
|
||||
await User.objects.create(name="maqo quidid")
|
||||
@ -651,8 +546,8 @@ async def test_start_and_end_filters():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_and_first():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await User.objects.create(name="Tom")
|
||||
await User.objects.create(name="Jane")
|
||||
await User.objects.create(name="Lucy")
|
||||
@ -681,4 +576,4 @@ async def test_get_and_first():
|
||||
def test_constraints():
|
||||
with pytest.raises(pydantic.ValidationError) as e:
|
||||
Product(name="T-Shirt", rating=50, in_stock=True)
|
||||
assert "ensure this value is less than or equal to 5" in str(e.value)
|
||||
assert "Input should be less than or equal to 5 " in str(e.value)
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
import pickle
|
||||
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()
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "users"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="users")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -24,28 +19,19 @@ class User(ormar.Model):
|
||||
|
||||
|
||||
class Post(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "posts"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="posts")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
created_by: Optional[User] = ormar.ForeignKey(User)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dumping_and_loading_model_works():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
user = await User(name="Test", properties={"aa": "bb"}).save()
|
||||
post = Post(name="Test post")
|
||||
await user.posts.add(post)
|
||||
|
||||
@ -1,52 +1,44 @@
|
||||
from typing import Dict, Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from pydantic import Json, PositiveInt, ValidationError
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
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 OverwriteTest(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "overwrites"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="overwrites")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
my_int: int = ormar.Integer(overwrite_pydantic_type=PositiveInt)
|
||||
constraint_dict: Json = ormar.JSON(
|
||||
overwrite_pydantic_type=Optional[Json[Dict[str, int]]] # type: ignore
|
||||
)
|
||||
overwrite_pydantic_type=Optional[Json[Dict[str, int]]]
|
||||
) # type: ignore
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_constraints():
|
||||
with pytest.raises(ValidationError) as e:
|
||||
OverwriteTest(my_int=-10)
|
||||
assert "ensure this value is greater than 0" in str(e.value)
|
||||
assert "Input should be greater than 0" in str(e.value)
|
||||
|
||||
with pytest.raises(ValidationError) as e:
|
||||
OverwriteTest(my_int=10, constraint_dict={"aa": "ab"})
|
||||
assert "value is not a valid integer" in str(e.value)
|
||||
assert (
|
||||
"Input should be a valid integer, unable to parse string as an integer"
|
||||
in str(e.value)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await OverwriteTest(my_int=5, constraint_dict={"aa": 123}).save()
|
||||
|
||||
test = await OverwriteTest.objects.get()
|
||||
|
||||
@ -2,28 +2,19 @@ import sqlite3
|
||||
from typing import Optional
|
||||
|
||||
import asyncpg
|
||||
import databases
|
||||
import pymysql
|
||||
import sqlalchemy
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
import ormar
|
||||
import pymysql
|
||||
import pytest
|
||||
from sqlalchemy import text
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
db = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = db
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class PrimaryModel(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "primary_models"
|
||||
ormar_config = base_ormar_config.copy(tablename="primary_models")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=255, index=True)
|
||||
@ -33,17 +24,12 @@ class PrimaryModel(ormar.Model):
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_models():
|
||||
async with db:
|
||||
async with base_ormar_config.database:
|
||||
primary = await PrimaryModel(
|
||||
name="Foo", some_text="Bar", some_other_text="Baz"
|
||||
).save()
|
||||
|
||||
@ -1,39 +1,32 @@
|
||||
import databases
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class AutoincrementModel(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
|
||||
|
||||
class NonAutoincrementModel(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True, autoincrement=False)
|
||||
|
||||
|
||||
class ExplicitNullableModel(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True, nullable=True)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_pk_field_is_not_null():
|
||||
for model in [AutoincrementModel, NonAutoincrementModel, ExplicitNullableModel]:
|
||||
assert not model.Meta.table.c.get("id").nullable
|
||||
assert not model.ormar_config.table.c.get("id").nullable
|
||||
|
||||
@ -1,79 +1,68 @@
|
||||
# type: ignore
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar import ModelDefinitionError, property_field
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
from pydantic import PydanticUserError, computed_field
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class Song(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "songs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="songs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
sort_order: int = ormar.Integer()
|
||||
|
||||
@property_field
|
||||
def sorted_name(self):
|
||||
@computed_field
|
||||
def sorted_name(self) -> str:
|
||||
return f"{self.sort_order}: {self.name}"
|
||||
|
||||
@property_field
|
||||
def sample(self):
|
||||
@computed_field
|
||||
def sample(self) -> str:
|
||||
return "sample"
|
||||
|
||||
@property_field
|
||||
def sample2(self):
|
||||
@computed_field
|
||||
def sample2(self) -> str:
|
||||
return "sample2"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sort_order_on_main_model():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Song.objects.create(name="Song 3", sort_order=3)
|
||||
await Song.objects.create(name="Song 1", sort_order=1)
|
||||
await Song.objects.create(name="Song 2", sort_order=2)
|
||||
|
||||
songs = await Song.objects.all()
|
||||
song_dict = [song.dict() for song in songs]
|
||||
song_dict = [song.model_dump() for song in songs]
|
||||
assert all("sorted_name" in x for x in song_dict)
|
||||
assert all(
|
||||
x["sorted_name"] == f"{x['sort_order']}: {x['name']}" for x in song_dict
|
||||
)
|
||||
song_json = [song.json() for song in songs]
|
||||
song_json = [song.model_dump_json() for song in songs]
|
||||
assert all("sorted_name" in x for x in song_json)
|
||||
|
||||
check_include = songs[0].dict(include={"sample"})
|
||||
check_include = songs[0].model_dump(include={"sample"})
|
||||
assert "sample" in check_include
|
||||
assert "sample2" not in check_include
|
||||
assert "sorted_name" not in check_include
|
||||
|
||||
check_include = songs[0].dict(exclude={"sample"})
|
||||
check_include = songs[0].model_dump(exclude={"sample"})
|
||||
assert "sample" not in check_include
|
||||
assert "sample2" in check_include
|
||||
assert "sorted_name" in check_include
|
||||
|
||||
|
||||
def test_wrong_definition():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
with pytest.raises(PydanticUserError):
|
||||
|
||||
class WrongModel(ormar.Model): # pragma: no cover
|
||||
@property_field
|
||||
@computed_field
|
||||
def test(self, aa=10, bb=30):
|
||||
pass
|
||||
|
||||
@ -1,31 +1,24 @@
|
||||
import random
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from pydantic import BaseModel, Field, HttpUrl, PaymentCardNumber
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
from pydantic import BaseModel, Field, HttpUrl
|
||||
from pydantic_extra_types.payment import PaymentCardNumber
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class ModelTest(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=200)
|
||||
url: HttpUrl = "https://www.example.com" # type: ignore
|
||||
number: Optional[PaymentCardNumber]
|
||||
number: Optional[PaymentCardNumber] = None
|
||||
|
||||
|
||||
CARD_NUMBERS = [
|
||||
@ -42,8 +35,7 @@ def get_number():
|
||||
|
||||
|
||||
class ModelTest2(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=200)
|
||||
@ -57,8 +49,7 @@ class PydanticTest(BaseModel):
|
||||
|
||||
|
||||
class ModelTest3(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
kwargs["number"] = get_number()
|
||||
@ -72,18 +63,12 @@ class ModelTest3(ormar.Model):
|
||||
pydantic_test: PydanticTest
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_working_with_pydantic_fields():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
test = ModelTest(name="Test")
|
||||
assert test.name == "Test"
|
||||
assert test.url == "https://www.example.com"
|
||||
@ -103,7 +88,7 @@ async def test_working_with_pydantic_fields():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_factory_for_pydantic_fields():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
test = ModelTest2(name="Test2", number="4000000000000002")
|
||||
assert test.name == "Test2"
|
||||
assert test.url == "https://www.example2.com"
|
||||
@ -123,7 +108,7 @@ async def test_default_factory_for_pydantic_fields():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_setting_for_pydantic_fields():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
test = ModelTest3(name="Test3")
|
||||
assert test.name == "Test3"
|
||||
assert test.url == "https://www.example3.com"
|
||||
|
||||
@ -1,32 +1,28 @@
|
||||
import datetime
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar import property_field
|
||||
from tests.settings import DATABASE_URL
|
||||
import pydantic
|
||||
import pytest
|
||||
from pydantic import computed_field
|
||||
|
||||
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()
|
||||
|
||||
|
||||
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)
|
||||
timestamp: datetime.datetime = ormar.DateTime(pydantic_only=True)
|
||||
timestamp: datetime.datetime = pydantic.Field(default=None)
|
||||
|
||||
@property_field
|
||||
@computed_field
|
||||
def name10(self) -> str:
|
||||
return self.name + "_10"
|
||||
|
||||
@property_field
|
||||
@computed_field
|
||||
def name20(self) -> str:
|
||||
return self.name + "_20"
|
||||
|
||||
@ -34,24 +30,18 @@ class Album(ormar.Model):
|
||||
def name30(self) -> str:
|
||||
return self.name + "_30"
|
||||
|
||||
@property_field
|
||||
@computed_field
|
||||
def name40(self) -> str:
|
||||
return self.name + "_40"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pydantic_only_fields():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
album = await Album.objects.create(name="Hitchcock")
|
||||
assert album.pk is not None
|
||||
assert album.saved
|
||||
@ -63,14 +53,14 @@ async def test_pydantic_only_fields():
|
||||
album = await Album.objects.fields({"name", "timestamp"}).get()
|
||||
assert album.timestamp is None
|
||||
|
||||
test_dict = album.dict()
|
||||
test_dict = album.model_dump()
|
||||
assert "timestamp" in test_dict
|
||||
assert test_dict["timestamp"] is None
|
||||
|
||||
assert album.name30 == "Hitchcock_30"
|
||||
|
||||
album.timestamp = datetime.datetime.now()
|
||||
test_dict = album.dict()
|
||||
test_dict = album.model_dump()
|
||||
assert "timestamp" in test_dict
|
||||
assert test_dict["timestamp"] is not None
|
||||
assert test_dict.get("name10") == "Hitchcock_10"
|
||||
|
||||
@ -1,24 +1,16 @@
|
||||
from typing import List
|
||||
|
||||
import databases
|
||||
import sqlalchemy
|
||||
import ormar
|
||||
from pydantic import PrivateAttr
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Subscription(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "subscriptions"
|
||||
ormar_config = base_ormar_config.copy(tablename="subscriptions")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
stripe_subscription_id: str = ormar.String(nullable=False, max_length=256)
|
||||
@ -29,6 +21,9 @@ class Subscription(ormar.Model):
|
||||
self._add_payments.append(payment)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_private_attribute():
|
||||
sub = Subscription(stripe_subscription_id="2312312sad231")
|
||||
sub.add_payment("test")
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
from typing import List
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
from ormar.exceptions import ModelPersistenceError
|
||||
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
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class NickNames(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "nicks"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -24,17 +19,11 @@ class NickNames(ormar.Model):
|
||||
|
||||
|
||||
class NicksHq(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "nicks_x_hq"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks_x_hq")
|
||||
|
||||
|
||||
class HQ(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "hqs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="hqs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -42,10 +31,7 @@ class HQ(ormar.Model):
|
||||
|
||||
|
||||
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, name="company_name")
|
||||
@ -53,19 +39,13 @@ class Company(ormar.Model):
|
||||
hq: HQ = ormar.ForeignKey(HQ)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_instantiation_false_save_true():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
comp = Company(name="Banzai", founded=1988)
|
||||
assert not comp.saved
|
||||
await comp.save()
|
||||
@ -74,8 +54,8 @@ async def test_instantiation_false_save_true():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saved_edited_not_saved():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
comp = await Company.objects.create(name="Banzai", founded=1988)
|
||||
assert comp.saved
|
||||
comp.name = "Banzai2"
|
||||
@ -96,8 +76,8 @@ async def test_saved_edited_not_saved():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_adding_related_gets_dirty():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
comp = await Company.objects.create(name="Banzai", founded=1988)
|
||||
assert comp.saved
|
||||
@ -123,8 +103,8 @@ async def test_adding_related_gets_dirty():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_adding_many_to_many_does_not_gets_dirty():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
nick1 = await NickNames.objects.create(name="Bazinga", is_lame=False)
|
||||
nick2 = await NickNames.objects.create(name="Bazinga2", is_lame=True)
|
||||
|
||||
@ -152,8 +132,8 @@ async def test_adding_many_to_many_does_not_gets_dirty():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
comp = await Company.objects.create(name="Banzai", founded=1988)
|
||||
assert comp.saved
|
||||
await comp.delete()
|
||||
@ -165,8 +145,8 @@ async def test_delete():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
comp = await Company.objects.create(name="Banzai", founded=1988)
|
||||
assert comp.saved
|
||||
comp.name = "AA"
|
||||
@ -179,8 +159,8 @@ async def test_load():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_queryset_methods():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await Company.objects.create(name="Banzai", founded=1988)
|
||||
await Company.objects.create(name="Yuhu", founded=1989)
|
||||
await Company.objects.create(name="Konono", founded=1990)
|
||||
@ -208,7 +188,7 @@ async def test_queryset_methods():
|
||||
assert comp3.pk == comp.pk
|
||||
assert created is False
|
||||
|
||||
update_dict = comp.dict()
|
||||
update_dict = comp.model_dump()
|
||||
update_dict["founded"] = 2010
|
||||
comp = await Company.objects.update_or_create(**update_dict)
|
||||
assert comp.saved
|
||||
@ -222,8 +202,8 @@ async def test_queryset_methods():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_bulk_methods():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
c1 = Company(name="Banzai", founded=1988)
|
||||
c2 = Company(name="Yuhu", founded=1989)
|
||||
|
||||
|
||||
@ -1,23 +1,16 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import sqlalchemy
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
db = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class PrimaryModel(ormar.Model):
|
||||
class Meta:
|
||||
metadata = metadata
|
||||
database = db
|
||||
tablename = "primary_models"
|
||||
ormar_config = base_ormar_config.copy(tablename="primary_models")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=255, index=True)
|
||||
@ -27,10 +20,7 @@ class PrimaryModel(ormar.Model):
|
||||
|
||||
|
||||
class SecondaryModel(ormar.Model):
|
||||
class Meta:
|
||||
metadata = metadata
|
||||
database = db
|
||||
tablename = "secondary_models"
|
||||
ormar_config = base_ormar_config.copy(tablename="secondary_models")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -39,18 +29,13 @@ class SecondaryModel(ormar.Model):
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_models():
|
||||
async with db:
|
||||
async with db.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
primary = await PrimaryModel(
|
||||
name="Foo", some_text="Bar", some_other_text="Baz"
|
||||
).save()
|
||||
|
||||
@ -1,24 +1,18 @@
|
||||
import asyncio
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from sqlalchemy import func, text
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
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 Product(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "product"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="product")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -27,25 +21,21 @@ class Product(ormar.Model):
|
||||
created: datetime = ormar.DateTime(server_default=func.now())
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_table_defined_properly():
|
||||
assert Product.Meta.model_fields["created"].nullable
|
||||
assert not Product.__fields__["created"].required
|
||||
assert Product.Meta.table.columns["created"].server_default.arg.name == "now"
|
||||
assert Product.ormar_config.model_fields["created"].nullable
|
||||
assert not Product.model_fields["created"].is_required()
|
||||
assert (
|
||||
Product.ormar_config.table.columns["created"].server_default.arg.name == "now"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_creation():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
p1 = Product(name="Test")
|
||||
assert p1.created is None
|
||||
await p1.save()
|
||||
|
||||
@ -1,36 +1,25 @@
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
from ormar.models import Model
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Comment(Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "comments"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="comments")
|
||||
|
||||
test: int = ormar.Integer(primary_key=True, comment="primary key of comments")
|
||||
test_string: str = ormar.String(max_length=250, comment="test that it works")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_comments_are_set_in_db():
|
||||
columns = Comment.Meta.table.c
|
||||
columns = Comment.ormar_config.table.c
|
||||
for c in columns:
|
||||
assert c.comment == Comment.Meta.model_fields[c.name].comment
|
||||
assert c.comment == Comment.ormar_config.model_fields[c.name].comment
|
||||
|
||||
@ -1,26 +1,16 @@
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
|
||||
import ormar
|
||||
import sqlalchemy
|
||||
import databases
|
||||
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 BaseMeta:
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config(force_rollback=True)
|
||||
|
||||
|
||||
class JimmyUser(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "jimmy_users"
|
||||
ormar_config = base_ormar_config.copy(tablename="jimmy_users")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(
|
||||
primary_key=True, default=uuid.uuid4(), uuid_format="string"
|
||||
@ -28,42 +18,31 @@ class JimmyUser(ormar.Model):
|
||||
|
||||
|
||||
class JimmyProfile(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "jimmy_profiles"
|
||||
ormar_config = base_ormar_config.copy(tablename="jimmy_profiles")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(
|
||||
primary_key=True, default=uuid.uuid4(), uuid_format="string"
|
||||
)
|
||||
name = ormar.String(max_length=42, default="JimmyProfile")
|
||||
|
||||
user: JimmyUser = ormar.ForeignKey(to=JimmyUser)
|
||||
|
||||
|
||||
class JimmyAccount(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "jimmy_accounts"
|
||||
ormar_config = base_ormar_config.copy(tablename="jimmy_accounts")
|
||||
|
||||
id: uuid.UUID = ormar.UUID(
|
||||
primary_key=True, default=uuid.uuid4(), uuid_format="string"
|
||||
)
|
||||
|
||||
name = ormar.String(max_length=42, default="JimmyAccount")
|
||||
|
||||
user: JimmyUser = ormar.ForeignKey(to=JimmyUser)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_excluding_one_relation():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
user = JimmyUser()
|
||||
await user.save()
|
||||
|
||||
@ -77,7 +56,7 @@ async def test_excluding_one_relation():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_excluding_other_relation():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
user = JimmyUser()
|
||||
await user.save()
|
||||
|
||||
|
||||
@ -1,24 +1,16 @@
|
||||
from typing import List
|
||||
|
||||
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
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
database = database
|
||||
metadata = metadata
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Language(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "languages"
|
||||
ormar_config = base_ormar_config.copy(tablename="languages")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -26,8 +18,7 @@ class Language(ormar.Model):
|
||||
|
||||
|
||||
class CringeLevel(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "levels"
|
||||
ormar_config = base_ormar_config.copy(tablename="levels")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -35,8 +26,7 @@ class CringeLevel(ormar.Model):
|
||||
|
||||
|
||||
class NickName(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "nicks"
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -45,8 +35,7 @@ class NickName(ormar.Model):
|
||||
|
||||
|
||||
class HQ(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "hqs"
|
||||
ormar_config = base_ormar_config.copy(tablename="hqs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -54,8 +43,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")
|
||||
@ -63,19 +51,13 @@ class Company(ormar.Model):
|
||||
hq: HQ = ormar.ForeignKey(HQ, related_name="companies")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_all_fk_rel():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
company = await Company.objects.create(name="Banzai", founded=1988, hq=hq)
|
||||
|
||||
@ -94,8 +76,8 @@ async def test_load_all_fk_rel():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_all_many_to_many():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
nick1 = await NickName.objects.create(name="BazingaO", is_lame=False)
|
||||
nick2 = await NickName.objects.create(name="Bazinga20", is_lame=True)
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
@ -120,8 +102,8 @@ async def test_load_all_many_to_many():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_all_with_order():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
nick1 = await NickName.objects.create(name="Barry", is_lame=False)
|
||||
nick2 = await NickName.objects.create(name="Joe", is_lame=True)
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
@ -154,8 +136,8 @@ async def test_load_all_with_order():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_loading_reversed_relation():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
await Company.objects.create(name="Banzai", founded=1988, hq=hq)
|
||||
|
||||
@ -170,8 +152,8 @@ async def test_loading_reversed_relation():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_loading_nested():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
language = await Language.objects.create(name="English")
|
||||
level = await CringeLevel.objects.create(name="High", language=language)
|
||||
level2 = await CringeLevel.objects.create(name="Low", language=language)
|
||||
|
||||
@ -1,31 +1,26 @@
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
import ormar
|
||||
from sqlalchemy import text
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
database = database
|
||||
metadata = metadata
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Task(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "tasks"
|
||||
ormar_config = base_ormar_config.copy(tablename="tasks")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(
|
||||
max_length=255, minimum=0, server_default=text("Default Name"), nullable=False
|
||||
max_length=255, minimum=0, server_default=text("'Default Name'"), nullable=False
|
||||
)
|
||||
points: int = ormar.Integer(
|
||||
default=0, minimum=0, server_default=text("0"), nullable=False
|
||||
)
|
||||
score: int = ormar.Integer(default=5)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_populate_default_values():
|
||||
@ -39,3 +34,4 @@ def test_populate_default_values():
|
||||
assert result["id"] is None
|
||||
assert result["name"] == ""
|
||||
assert result["points"] == 0
|
||||
assert result["score"] == 5
|
||||
|
||||
@ -1,31 +1,23 @@
|
||||
from typing import List
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class CringeLevel(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "levels"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="levels")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class NickName(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "nicks"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -34,17 +26,11 @@ class NickName(ormar.Model):
|
||||
|
||||
|
||||
class NicksHq(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "nicks_x_hq"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks_x_hq")
|
||||
|
||||
|
||||
class HQ(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "hqs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="hqs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -52,10 +38,7 @@ class HQ(ormar.Model):
|
||||
|
||||
|
||||
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, name="company_name")
|
||||
@ -63,19 +46,13 @@ class Company(ormar.Model):
|
||||
hq: HQ = ormar.ForeignKey(HQ, related_name="companies")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_related_fk_rel():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
comp = await Company.objects.create(name="Banzai", founded=1988, hq=hq)
|
||||
assert comp.saved
|
||||
@ -102,8 +79,8 @@ async def test_saving_related_fk_rel():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_many_to_many():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
nick1 = await NickName.objects.create(name="BazingaO", is_lame=False)
|
||||
nick2 = await NickName.objects.create(name="Bazinga20", is_lame=True)
|
||||
|
||||
@ -144,8 +121,8 @@ async def test_saving_many_to_many():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_reversed_relation():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
hq = await HQ.objects.create(name="Main")
|
||||
await Company.objects.create(name="Banzai", founded=1988, hq=hq)
|
||||
|
||||
@ -185,8 +162,8 @@ async def test_saving_reversed_relation():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_nested():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
level = await CringeLevel.objects.create(name="High")
|
||||
level2 = await CringeLevel.objects.create(name="Low")
|
||||
nick1 = await NickName.objects.create(
|
||||
|
||||
@ -1,31 +1,23 @@
|
||||
from typing import List
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class CringeLevel(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "levels"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="levels")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class NickName(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "nicks"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -34,20 +26,14 @@ class NickName(ormar.Model):
|
||||
|
||||
|
||||
class NicksHq(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "nicks_x_hq"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="nicks_x_hq")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
new_field: str = ormar.String(max_length=200, nullable=True)
|
||||
|
||||
|
||||
class HQ(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "hqs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="hqs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
|
||||
@ -55,10 +41,7 @@ class HQ(ormar.Model):
|
||||
|
||||
|
||||
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, name="company_name")
|
||||
@ -66,19 +49,13 @@ class Company(ormar.Model):
|
||||
hq: HQ = ormar.ForeignKey(HQ, related_name="companies")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_related_reverse_fk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
payload = {"companies": [{"name": "Banzai"}], "name": "Main"}
|
||||
hq = HQ(**payload)
|
||||
count = await hq.save_related(follow=True, save_all=True)
|
||||
@ -94,8 +71,8 @@ async def test_saving_related_reverse_fk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_related_reverse_fk_multiple():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
payload = {
|
||||
"companies": [{"name": "Banzai"}, {"name": "Yamate"}],
|
||||
"name": "Main",
|
||||
@ -116,8 +93,8 @@ async def test_saving_related_reverse_fk_multiple():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_related_fk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
payload = {"hq": {"name": "Main"}, "name": "Banzai"}
|
||||
comp = Company(**payload)
|
||||
count = await comp.save_related(follow=True, save_all=True)
|
||||
@ -132,8 +109,8 @@ async def test_saving_related_fk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_many_to_many_wo_through():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
payload = {
|
||||
"name": "Main",
|
||||
"nicks": [
|
||||
@ -155,9 +132,9 @@ async def test_saving_many_to_many_wo_through():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_many_to_many_with_through():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
payload = {
|
||||
"name": "Main",
|
||||
"nicks": [
|
||||
@ -189,8 +166,8 @@ async def test_saving_many_to_many_with_through():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_nested_with_m2m_and_rev_fk():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
payload = {
|
||||
"name": "Main",
|
||||
"nicks": [
|
||||
@ -214,8 +191,8 @@ async def test_saving_nested_with_m2m_and_rev_fk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_nested_with_m2m_and_rev_fk_and_through():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
payload = {
|
||||
"hq": {
|
||||
"name": "Yoko",
|
||||
|
||||
@ -1,30 +1,24 @@
|
||||
import uuid
|
||||
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()
|
||||
|
||||
|
||||
class Department(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4)
|
||||
department_name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Course(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4)
|
||||
course_name: str = ormar.String(max_length=100)
|
||||
@ -33,27 +27,19 @@ class Course(ormar.Model):
|
||||
|
||||
|
||||
class Student(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4)
|
||||
name: str = ormar.String(max_length=100)
|
||||
courses = ormar.ManyToMany(Course)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uuid_pk_in_save_related():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
to_save = {
|
||||
"department_name": "Ormar",
|
||||
"courses": [
|
||||
@ -80,4 +66,4 @@ async def test_uuid_pk_in_save_related():
|
||||
"id": ...,
|
||||
"courses": {"id": ..., "students": {"id", "studentcourse"}},
|
||||
}
|
||||
assert department_check.dict(exclude=to_exclude) == to_save
|
||||
assert department_check.model_dump(exclude=to_exclude) == to_save
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
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()
|
||||
|
||||
|
||||
class Director(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "directors"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="directors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="first_name")
|
||||
@ -23,10 +18,7 @@ class Director(ormar.Model):
|
||||
|
||||
|
||||
class Movie(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "movies"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="movies")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="title")
|
||||
@ -35,18 +27,12 @@ class Movie(ormar.Model):
|
||||
director: Optional[Director] = ormar.ForeignKey(Director)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_updating_selected_columns():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
director1 = await Director(name="Peter", last_name="Jackson").save()
|
||||
director2 = await Director(name="James", last_name="Cameron").save()
|
||||
|
||||
@ -82,7 +68,7 @@ async def test_updating_selected_columns():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_not_passing_columns_or_empty_list_saves_all():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
director = await Director(name="James", last_name="Cameron").save()
|
||||
terminator = await Movie(
|
||||
name="Terminator", year=1984, director=director, profit=0.078
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
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()
|
||||
|
||||
|
||||
class Director(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "directors"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="directors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="first_name")
|
||||
@ -23,10 +18,7 @@ class Director(ormar.Model):
|
||||
|
||||
|
||||
class Movie(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "movies"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="movies")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100, nullable=False, name="title")
|
||||
@ -35,18 +27,12 @@ class Movie(ormar.Model):
|
||||
director: Optional[Director] = ormar.ForeignKey(Director)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_updating_selected_columns():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
director1 = await Director(name="Peter", last_name="Jackson").save()
|
||||
|
||||
await Movie(
|
||||
|
||||
@ -1,35 +1,26 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
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)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
orders_by = ["-name"]
|
||||
ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"])
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Book(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
orders_by = ["year", "-ranking"]
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="books", order_by=["year", "-ranking"]
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author: Optional[Author] = ormar.ForeignKey(Author)
|
||||
@ -38,26 +29,20 @@ class Book(ormar.Model):
|
||||
ranking: int = ormar.Integer(nullable=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(autouse=True, scope="function")
|
||||
async def cleanup():
|
||||
yield
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Book.objects.delete(each=True)
|
||||
await Author.objects.delete(each=True)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_orders_is_applied():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
tolkien = await Author(name="J.R.R. Tolkien").save()
|
||||
sapkowski = await Author(name="Andrzej Sapkowski").save()
|
||||
king = await Author(name="Stephen King").save()
|
||||
@ -78,7 +63,7 @@ async def test_default_orders_is_applied():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_orders_is_applied_on_related():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
tolkien = await Author(name="J.R.R. Tolkien").save()
|
||||
silmarillion = await Book(
|
||||
author=tolkien, title="The Silmarillion", year=1977
|
||||
@ -101,7 +86,7 @@ async def test_default_orders_is_applied_on_related():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_orders_is_applied_on_related_two_fields():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
sanders = await Author(name="Brandon Sanderson").save()
|
||||
twok = await Book(
|
||||
author=sanders, title="The Way of Kings", year=2010, ranking=10
|
||||
|
||||
@ -1,34 +1,25 @@
|
||||
from typing import List, Optional
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
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)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Book(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
ormar_config = base_ormar_config.copy(tablename="books")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author: Optional[Author] = ormar.ForeignKey(
|
||||
@ -40,8 +31,7 @@ class Book(ormar.Model):
|
||||
|
||||
|
||||
class Animal(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "animals"
|
||||
ormar_config = base_ormar_config.copy(tablename="animals")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
name: str = ormar.String(max_length=200)
|
||||
@ -49,8 +39,7 @@ class Animal(ormar.Model):
|
||||
|
||||
|
||||
class Human(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "humans"
|
||||
ormar_config = base_ormar_config.copy(tablename="humans")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
@ -62,26 +51,20 @@ class Human(ormar.Model):
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(autouse=True, scope="function")
|
||||
async def cleanup():
|
||||
yield
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Book.objects.delete(each=True)
|
||||
await Author.objects.delete(each=True)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_orders_is_applied_from_reverse_relation():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
tolkien = await Author(name="J.R.R. Tolkien").save()
|
||||
hobbit = await Book(author=tolkien, title="The Hobbit", year=1933).save()
|
||||
silmarillion = await Book(
|
||||
@ -99,7 +82,7 @@ async def test_default_orders_is_applied_from_reverse_relation():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_orders_is_applied_from_relation():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
bret = await Author(name="Peter V. Bret").save()
|
||||
tds = await Book(
|
||||
author=bret, title="The Desert Spear", year=2010, ranking=9
|
||||
@ -116,7 +99,7 @@ async def test_default_orders_is_applied_from_relation():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_orders_is_applied_from_relation_on_m2m():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
alice = await Human(name="Alice").save()
|
||||
|
||||
spot = await Animal(name="Spot", specie="Cat").save()
|
||||
@ -135,8 +118,7 @@ async def test_default_orders_is_applied_from_relation_on_m2m():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_orders_is_applied_from_reverse_relation_on_m2m():
|
||||
async with database:
|
||||
|
||||
async with base_ormar_config.database:
|
||||
max = await Animal(name="Max", specie="Dog").save()
|
||||
joe = await Human(name="Joe").save()
|
||||
zack = await Human(name="Zack").save()
|
||||
|
||||
@ -1,27 +1,25 @@
|
||||
from typing import Any, Dict, List, Tuple, Type, cast
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar import ModelDefinitionError, Model, QuerySet, pre_relation_remove, pre_update
|
||||
from ormar import pre_save
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
from ormar import (
|
||||
Model,
|
||||
ModelDefinitionError,
|
||||
QuerySet,
|
||||
pre_relation_remove,
|
||||
pre_save,
|
||||
pre_update,
|
||||
)
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Animal(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "animals"
|
||||
ormar_config = base_ormar_config.copy(tablename="animals")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
@ -29,8 +27,7 @@ class Animal(ormar.Model):
|
||||
|
||||
|
||||
class Link(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "link_table"
|
||||
ormar_config = base_ormar_config.copy(tablename="link_table")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
animal_order: int = ormar.Integer(nullable=True)
|
||||
@ -38,8 +35,7 @@ class Link(ormar.Model):
|
||||
|
||||
|
||||
class Human(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "humans"
|
||||
ormar_config = base_ormar_config.copy(tablename="humans")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
@ -53,8 +49,7 @@ class Human(ormar.Model):
|
||||
|
||||
|
||||
class Human2(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "humans2"
|
||||
ormar_config = base_ormar_config.copy(tablename="humans2")
|
||||
|
||||
id: UUID = ormar.UUID(primary_key=True, default=uuid4)
|
||||
name: str = ormar.Text(default="")
|
||||
@ -63,18 +58,12 @@ class Human2(ormar.Model):
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ordering_by_through_fail():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
alice = await Human2(name="Alice").save()
|
||||
spot = await Animal(name="Spot").save()
|
||||
await alice.favoriteAnimals.add(spot)
|
||||
@ -99,8 +88,8 @@ def _get_through_model_relations(
|
||||
sender: Type[Model], instance: Model
|
||||
) -> Tuple[Type[Model], Type[Model]]:
|
||||
relations = list(instance.extract_related_names())
|
||||
rel_one = sender.Meta.model_fields[relations[0]].to
|
||||
rel_two = sender.Meta.model_fields[relations[1]].to
|
||||
rel_one = sender.ormar_config.model_fields[relations[0]].to
|
||||
rel_two = sender.ormar_config.model_fields[relations[1]].to
|
||||
return rel_one, rel_two
|
||||
|
||||
|
||||
@ -223,7 +212,7 @@ async def reorder_links_on_remove(
|
||||
|
||||
Note that if classes have many relations you need to check if current one is ordered
|
||||
"""
|
||||
through_class = sender.Meta.model_fields[relation_name].through
|
||||
through_class = sender.ormar_config.model_fields[relation_name].through
|
||||
through_instance = getattr(instance, through_class.get_name())
|
||||
if not through_instance:
|
||||
parent_pk = instance.pk
|
||||
@ -249,7 +238,7 @@ async def reorder_links_on_remove(
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ordering_by_through_on_m2m_field():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
|
||||
def verify_order(instance, expected):
|
||||
field_name = (
|
||||
|
||||
@ -1,34 +1,24 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
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)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Book(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
orders_by = ["-ranking"]
|
||||
ormar_config = base_ormar_config.copy(tablename="books", order_by=["-ranking"])
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author: Optional[Author] = ormar.ForeignKey(
|
||||
@ -39,26 +29,20 @@ class Book(ormar.Model):
|
||||
ranking: int = ormar.Integer(nullable=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(autouse=True, scope="function")
|
||||
async def cleanup():
|
||||
yield
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Book.objects.delete(each=True)
|
||||
await Author.objects.delete(each=True)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_orders_is_applied_from_reverse_relation():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
tolkien = await Author(name="J.R.R. Tolkien").save()
|
||||
hobbit = await Book(author=tolkien, title="The Hobbit", year=1933).save()
|
||||
silmarillion = await Book(
|
||||
|
||||
@ -1,31 +1,23 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
import asyncio
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Department(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Course(ormar.Model):
|
||||
class Meta:
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -33,18 +25,12 @@ class Course(ormar.Model):
|
||||
department: Optional[Department] = ormar.ForeignKey(Department)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_adding_relation_to_reverse_saves_the_child():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
department = await Department(name="Science").save()
|
||||
course = Course(name="Math", completed=False)
|
||||
|
||||
|
||||
@ -1,36 +1,27 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar.exceptions import QueryDefinitionError
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
order_by = ["-name"]
|
||||
ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"])
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Book(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
order_by = ["year", "-ranking"]
|
||||
ormar_config = base_ormar_config.copy(
|
||||
tablename="books", order_by=["year", "-ranking"]
|
||||
)
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author: Optional[Author] = ormar.ForeignKey(Author)
|
||||
@ -39,19 +30,13 @@ class Book(ormar.Model):
|
||||
ranking: int = ormar.Integer(nullable=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(autouse=True, scope="function")
|
||||
async def cleanup():
|
||||
yield
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Book.objects.delete(each=True)
|
||||
await Author.objects.delete(each=True)
|
||||
|
||||
@ -65,7 +50,7 @@ async def sample_data():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_min_method():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await sample_data()
|
||||
assert await Book.objects.min("year") == 1920
|
||||
result = await Book.objects.min(["year", "ranking"])
|
||||
@ -89,7 +74,7 @@ async def test_min_method():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_max_method():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await sample_data()
|
||||
assert await Book.objects.max("year") == 1930
|
||||
result = await Book.objects.max(["year", "ranking"])
|
||||
@ -113,7 +98,7 @@ async def test_max_method():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sum_method():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await sample_data()
|
||||
assert await Book.objects.sum("year") == 5773
|
||||
result = await Book.objects.sum(["year", "ranking"])
|
||||
@ -138,7 +123,7 @@ async def test_sum_method():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_avg_method():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await sample_data()
|
||||
assert round(float(await Book.objects.avg("year")), 2) == 1924.33
|
||||
result = await Book.objects.avg(["year", "ranking"])
|
||||
@ -166,7 +151,7 @@ async def test_avg_method():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_queryset_method():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await sample_data()
|
||||
author = await Author.objects.select_related("books").get()
|
||||
assert await author.books.min("year") == 1920
|
||||
@ -180,7 +165,7 @@ async def test_queryset_method():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_count_method():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await sample_data()
|
||||
|
||||
count = await Author.objects.select_related("books").count()
|
||||
|
||||
@ -1,20 +1,15 @@
|
||||
import databases
|
||||
import ormar
|
||||
import pytest
|
||||
from sqlalchemy import func
|
||||
|
||||
import ormar
|
||||
import sqlalchemy
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Chart(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "charts"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="charts")
|
||||
|
||||
chart_id = ormar.Integer(primary_key=True, autoincrement=True)
|
||||
name = ormar.String(max_length=200, unique=True, index=True)
|
||||
@ -28,10 +23,7 @@ class Chart(ormar.Model):
|
||||
|
||||
|
||||
class Report(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "reports"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="reports")
|
||||
|
||||
report_id = ormar.Integer(primary_key=True, autoincrement=True)
|
||||
name = ormar.String(max_length=200, unique=True, index=True)
|
||||
@ -40,10 +32,7 @@ class Report(ormar.Model):
|
||||
|
||||
|
||||
class Language(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "languages"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="languages")
|
||||
|
||||
language_id = ormar.Integer(primary_key=True, autoincrement=True)
|
||||
code = ormar.String(max_length=5)
|
||||
@ -51,20 +40,14 @@ class Language(ormar.Model):
|
||||
|
||||
|
||||
class TranslationNode(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "translation_nodes"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="translation_nodes")
|
||||
|
||||
node_id = ormar.Integer(primary_key=True, autoincrement=True)
|
||||
node_type = ormar.String(max_length=200)
|
||||
|
||||
|
||||
class Translation(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "translations"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="translations")
|
||||
|
||||
translation_id = ormar.Integer(primary_key=True, autoincrement=True)
|
||||
node_id = ormar.ForeignKey(TranslationNode, related_name="translations")
|
||||
@ -73,10 +56,7 @@ class Translation(ormar.Model):
|
||||
|
||||
|
||||
class Filter(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "filters"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="filters")
|
||||
|
||||
filter_id = ormar.Integer(primary_key=True, autoincrement=True)
|
||||
name = ormar.String(max_length=200, unique=True, index=True)
|
||||
@ -90,10 +70,7 @@ class Filter(ormar.Model):
|
||||
|
||||
|
||||
class FilterValue(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "filter_values"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="filter_values")
|
||||
|
||||
value_id = ormar.Integer(primary_key=True, autoincrement=True)
|
||||
value = ormar.String(max_length=300)
|
||||
@ -103,10 +80,7 @@ class FilterValue(ormar.Model):
|
||||
|
||||
|
||||
class FilterXReport(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "filters_x_reports"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="filters_x_reports")
|
||||
|
||||
filter_x_report_id = ormar.Integer(primary_key=True)
|
||||
filter = ormar.ForeignKey(Filter, name="filter_id", related_name="reports")
|
||||
@ -117,10 +91,7 @@ class FilterXReport(ormar.Model):
|
||||
|
||||
|
||||
class ChartXReport(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "charts_x_reports"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="charts_x_reports")
|
||||
|
||||
chart_x_report_id = ormar.Integer(primary_key=True)
|
||||
chart = ormar.ForeignKey(Chart, name="chart_id", related_name="reports")
|
||||
@ -130,10 +101,7 @@ class ChartXReport(ormar.Model):
|
||||
|
||||
|
||||
class ChartColumn(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "charts_columns"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="charts_columns")
|
||||
|
||||
column_id = ormar.Integer(primary_key=True, autoincrement=True)
|
||||
chart = ormar.ForeignKey(Chart, name="chart_id", related_name="columns")
|
||||
@ -142,17 +110,11 @@ class ChartColumn(ormar.Model):
|
||||
translation = ormar.ForeignKey(TranslationNode, name="translation_node_id")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_saving_related_fk_rel():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
await Report.objects.select_all(follow=True).all()
|
||||
|
||||
@ -1,31 +1,22 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Book(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
ormar_config = base_ormar_config.copy(tablename="books")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author: Optional[Author] = ormar.ForeignKey(Author)
|
||||
@ -33,6 +24,9 @@ class Book(ormar.Model):
|
||||
year: int = ormar.Integer(nullable=True)
|
||||
|
||||
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
def test_or_group():
|
||||
result = ormar.or_(name="aa", books__title="bb")
|
||||
result.resolve(model_cls=Author)
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
from datetime import datetime
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Node(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "node"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="node")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=120)
|
||||
@ -24,10 +19,7 @@ class Node(ormar.Model):
|
||||
|
||||
|
||||
class Edge(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "edge"
|
||||
database = database
|
||||
metadata = metadata
|
||||
ormar_config = base_ormar_config.copy(tablename="edge")
|
||||
|
||||
id: str = ormar.String(primary_key=True, max_length=12)
|
||||
src_node: Node = ormar.ForeignKey(Node, related_name="next_edges")
|
||||
@ -36,18 +28,12 @@ class Edge(ormar.Model):
|
||||
created_at: datetime = ormar.DateTime(timezone=True, default=datetime.now)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sort_order_on_main_model():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
node1 = await Node(name="Node 1").save()
|
||||
node2 = await Node(name="Node 2").save()
|
||||
node3 = await Node(name="Node 3").save()
|
||||
|
||||
@ -1,32 +1,23 @@
|
||||
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)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Book(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
ormar_config = base_ormar_config.copy(tablename="books")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author: Optional[Author] = ormar.ForeignKey(Author)
|
||||
@ -35,10 +26,7 @@ class Book(ormar.Model):
|
||||
|
||||
|
||||
class JsonModel(ormar.Model):
|
||||
class Meta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
tablename = "jsons"
|
||||
ormar_config = base_ormar_config.copy(tablename="jsons")
|
||||
|
||||
id = ormar.Integer(primary_key=True)
|
||||
text_field = ormar.Text(nullable=True)
|
||||
@ -46,18 +34,12 @@ class JsonModel(ormar.Model):
|
||||
json_not_null = ormar.JSON()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_is_null():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
tolkien = await Author.objects.create(name="J.R.R. Tolkien")
|
||||
await Book.objects.create(author=tolkien, title="The Hobbit")
|
||||
await Book.objects.create(
|
||||
@ -99,7 +81,7 @@ async def test_is_null():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_isnull_json():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
author = await JsonModel.objects.create(json_not_null=None)
|
||||
assert author.json_field is None
|
||||
non_null_text_fields = await JsonModel.objects.all(text_field__isnull=False)
|
||||
|
||||
@ -1,32 +1,23 @@
|
||||
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)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class DataSource(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "datasources"
|
||||
ormar_config = base_ormar_config.copy(tablename="datasources")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=200, unique=True, index=True)
|
||||
|
||||
|
||||
class DataSourceTable(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "source_tables"
|
||||
ormar_config = base_ormar_config.copy(tablename="source_tables")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=200, index=True)
|
||||
@ -36,8 +27,7 @@ class DataSourceTable(ormar.Model):
|
||||
|
||||
|
||||
class DataSourceTableColumn(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "source_columns"
|
||||
ormar_config = base_ormar_config.copy(tablename="source_columns")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=200, index=True)
|
||||
@ -47,18 +37,12 @@ class DataSourceTableColumn(ormar.Model):
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database(): # pragma: no cover
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_double_nested_reverse_relation():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
data_source = await DataSource(name="local").save()
|
||||
test_tables = [
|
||||
{
|
||||
|
||||
@ -1,49 +1,34 @@
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from typing import Optional
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
import pytest
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Chart(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
datasets = ormar.JSON()
|
||||
|
||||
|
||||
class Config(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
ormar_config = base_ormar_config.copy(tablename="books")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
chart: Optional[Chart] = ormar.ForeignKey(Chart)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_field_that_is_not_relation_is_not_merged():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
chart = await Chart.objects.create(datasets=[{"test": "ok"}])
|
||||
await Config.objects.create(chart=chart)
|
||||
await Config.objects.create(chart=chart)
|
||||
|
||||
@ -1,33 +1,24 @@
|
||||
from typing import Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
import pytest
|
||||
from ormar.exceptions import QueryDefinitionError
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
from tests.lifespan import init_tests
|
||||
from tests.settings import create_config
|
||||
|
||||
|
||||
class BaseMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Author(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "authors"
|
||||
ormar_config = base_ormar_config.copy(tablename="authors")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Book(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "books"
|
||||
ormar_config = base_ormar_config.copy(tablename="books")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
author: Optional[Author] = ormar.ForeignKey(Author)
|
||||
@ -35,18 +26,12 @@ class Book(ormar.Model):
|
||||
year: int = ormar.Integer(nullable=True)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_or_filters():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
tolkien = await Author(name="J.R.R. Tolkien").save()
|
||||
await Book(author=tolkien, title="The Hobbit", year=1933).save()
|
||||
await Book(author=tolkien, title="The Lord of the Rings", year=1955).save()
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
from typing import List, 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()
|
||||
|
||||
|
||||
class Song(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "songs"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="songs")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -23,30 +18,21 @@ class Song(ormar.Model):
|
||||
|
||||
|
||||
class Owner(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "owners"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="owners")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class AliasNested(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "aliases_nested"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="aliases_nested")
|
||||
|
||||
id: int = ormar.Integer(name="alias_id", primary_key=True)
|
||||
name: str = ormar.String(name="alias_name", max_length=100)
|
||||
|
||||
|
||||
class AliasTest(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "aliases"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="aliases")
|
||||
|
||||
id: int = ormar.Integer(name="alias_id", primary_key=True)
|
||||
name: str = ormar.String(name="alias_name", max_length=100)
|
||||
@ -54,10 +40,7 @@ class AliasTest(ormar.Model):
|
||||
|
||||
|
||||
class Toy(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "toys"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="toys")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -65,20 +48,14 @@ class Toy(ormar.Model):
|
||||
|
||||
|
||||
class Factory(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "factories"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="factories")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class Car(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "cars"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="cars")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
@ -86,28 +63,19 @@ class Car(ormar.Model):
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "users"
|
||||
metadata = metadata
|
||||
database = database
|
||||
ormar_config = base_ormar_config.copy(tablename="users")
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
cars: List[Car] = ormar.ManyToMany(Car)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sort_order_on_main_model():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
await Song.objects.create(name="Song 3", sort_order=3)
|
||||
await Song.objects.create(name="Song 1", sort_order=1)
|
||||
await Song.objects.create(name="Song 2", sort_order=2)
|
||||
@ -166,7 +134,7 @@ async def test_sort_order_on_main_model():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sort_order_on_related_model():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
aphrodite = await Owner.objects.create(name="Aphrodite")
|
||||
hermes = await Owner.objects.create(name="Hermes")
|
||||
zeus = await Owner.objects.create(name="Zeus")
|
||||
@ -252,7 +220,7 @@ async def test_sort_order_on_related_model():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sort_order_on_many_to_many():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
factory1 = await Factory.objects.create(name="Factory 1")
|
||||
factory2 = await Factory.objects.create(name="Factory 2")
|
||||
|
||||
@ -326,7 +294,7 @@ async def test_sort_order_on_many_to_many():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sort_order_with_aliases():
|
||||
async with database:
|
||||
async with base_ormar_config.database:
|
||||
al1 = await AliasTest.objects.create(name="Test4")
|
||||
al2 = await AliasTest.objects.create(name="Test2")
|
||||
al3 = await AliasTest.objects.create(name="Test1")
|
||||
|
||||
@ -1,56 +1,39 @@
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
from ormar import ModelMeta
|
||||
import pytest
|
||||
from ormar.exceptions import QueryDefinitionError
|
||||
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(ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
base_ormar_config = create_config()
|
||||
|
||||
|
||||
class Car(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
|
||||
|
||||
class UsersCar(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
tablename = "cars_x_users"
|
||||
ormar_config = base_ormar_config.copy(tablename="cars_x_users")
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta(BaseMeta):
|
||||
pass
|
||||
ormar_config = base_ormar_config.copy()
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
cars = ormar.ManyToMany(Car, through=UsersCar)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||
metadata.drop_all(engine)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
create_test_database = init_tests(base_ormar_config)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_limit_zero():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
for i in range(5):
|
||||
await Car(name=f"{i}").save()
|
||||
|
||||
@ -61,8 +44,8 @@ async def test_limit_zero():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pagination_errors():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
with pytest.raises(QueryDefinitionError):
|
||||
await Car.objects.paginate(0).all()
|
||||
|
||||
@ -72,8 +55,8 @@ async def test_pagination_errors():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pagination_on_single_model():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
for i in range(20):
|
||||
await Car(name=f"{i}").save()
|
||||
|
||||
@ -96,8 +79,8 @@ async def test_pagination_on_single_model():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_proxy_pagination():
|
||||
async with database:
|
||||
async with database.transaction(force_rollback=True):
|
||||
async with base_ormar_config.database:
|
||||
async with base_ormar_config.database.transaction(force_rollback=True):
|
||||
user = await User(name="Jon").save()
|
||||
|
||||
for i in range(20):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user