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:
collerek
2024-03-23 19:28:28 +01:00
committed by GitHub
parent 3a206dd8dc
commit 500625f0ec
294 changed files with 8132 additions and 9311 deletions

33
tests/lifespan.py Normal file
View 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

View File

@ -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_,
)

View File

@ -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()

View File

@ -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()

View File

@ -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"

View File

@ -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"]

View File

@ -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)

View File

@ -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": [],
},

View File

@ -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",
}

View File

@ -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"}

View File

@ -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):

View File

@ -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)

View File

@ -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",
}

View File

@ -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",

View File

@ -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"

View File

@ -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")

View File

@ -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

View File

@ -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"
]

View File

@ -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,
}

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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()
)

View File

@ -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"
)

View File

@ -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

View File

@ -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)

View File

@ -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()]

View File

@ -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

View File

@ -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()

View File

@ -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,

View File

@ -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}"

View File

@ -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

View File

@ -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"})

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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"}

View File

@ -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")

View File

@ -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()

View File

@ -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")

View File

@ -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"]

View File

@ -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)

View File

@ -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)

View File

@ -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
)

View File

@ -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"
)

View File

@ -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")

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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")

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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(

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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()

View File

@ -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 = (

View File

@ -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(

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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 = [
{

View File

@ -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)

View File

@ -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()

View File

@ -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")

View File

@ -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