From 299a35a14df40505fa742ba7587c1fe1e8869939 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Fri, 14 Oct 2022 15:07:25 +1300 Subject: [PATCH 01/13] test: initial async tests - wip squashed wip commits based on `docs_src/tutorial` Goals --------- convert to async as working examples ensure static typing with mypy passes --- docs_src/tutorial_async/__init__.py | 0 .../tutorial_async/connect_async/__init__.py | 0 .../create_tables_async/__init__.py | 0 .../create_tables_async/tutorial001_async.py | 45 ++++++++ .../connect_async/delete_async/__init__.py | 0 .../delete_async/tutorial001_async.py | 91 ++++++++++++++++ .../connect_async/insert_async/__init__.py | 0 .../insert_async/tutorial001_async.py | 80 ++++++++++++++ .../connect_async/select_async/__init__.py | 0 .../select_async/tutorial001_async.py | 89 ++++++++++++++++ .../select_async/tutorial002_async.py | 89 ++++++++++++++++ .../select_async/tutorial003_async.py | 89 ++++++++++++++++ .../select_async/tutorial004_async.py | 89 ++++++++++++++++ .../select_async/tutorial005_async.py | 89 ++++++++++++++++ .../connect_async/update_async/__init__.py | 0 .../connect_async/update_async/tutorial001.py | 75 +++++++++++++ .../tutorial_async/select_async/__init__.py | 0 .../annotations/en/tutorial002.md | 63 +++++++++++ .../select_async/tutorial001_async.py | 62 +++++++++++ .../select_async/tutorial002_async.py | 62 +++++++++++ .../select_async/tutorial003_async.py | 61 +++++++++++ .../select_async/tutorial004_async.py | 62 +++++++++++ .../test_async_connect/__init__.py | 0 .../__init__.py | 0 .../test_async_tutorial001.py | 42 ++++++++ .../test_async_delete/__init__.py | 0 .../test_async_tutorial001.py | 79 ++++++++++++++ .../test_async_insert/__init__.py | 0 .../test_async_tutorial001.py | 59 +++++++++++ .../test_async_select/__init__.py | 0 .../test_async_tutorial001_tutorial002.py | 100 ++++++++++++++++++ .../test_async_tutorial003.py | 95 +++++++++++++++++ .../test_async_tutorial004.py | 69 ++++++++++++ .../test_async_tutorial005.py | 71 +++++++++++++ .../test_async_select/__init__.py | 0 .../test_async_tutorial001_tutorial002.py | 62 +++++++++++ .../test_async_tutorial003_tutorial004.py | 65 ++++++++++++ 37 files changed, 1688 insertions(+) create mode 100644 docs_src/tutorial_async/__init__.py create mode 100644 docs_src/tutorial_async/connect_async/__init__.py create mode 100644 docs_src/tutorial_async/connect_async/create_tables_async/__init__.py create mode 100644 docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py create mode 100644 docs_src/tutorial_async/connect_async/delete_async/__init__.py create mode 100644 docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py create mode 100644 docs_src/tutorial_async/connect_async/insert_async/__init__.py create mode 100644 docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py create mode 100644 docs_src/tutorial_async/connect_async/select_async/__init__.py create mode 100644 docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py create mode 100644 docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py create mode 100644 docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py create mode 100644 docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py create mode 100644 docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py create mode 100644 docs_src/tutorial_async/connect_async/update_async/__init__.py create mode 100644 docs_src/tutorial_async/connect_async/update_async/tutorial001.py create mode 100644 docs_src/tutorial_async/select_async/__init__.py create mode 100644 docs_src/tutorial_async/select_async/annotations/en/tutorial002.md create mode 100644 docs_src/tutorial_async/select_async/tutorial001_async.py create mode 100644 docs_src/tutorial_async/select_async/tutorial002_async.py create mode 100644 docs_src/tutorial_async/select_async/tutorial003_async.py create mode 100644 docs_src/tutorial_async/select_async/tutorial004_async.py create mode 100644 tests/test_async_tutorial/test_async_connect/__init__.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/__init__.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_delete/__init__.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_insert/__init__.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_select/__init__.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py create mode 100644 tests/test_async_tutorial/test_async_select/__init__.py create mode 100644 tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py create mode 100644 tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py diff --git a/docs_src/tutorial_async/__init__.py b/docs_src/tutorial_async/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/tutorial_async/connect_async/__init__.py b/docs_src/tutorial_async/connect_async/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/tutorial_async/connect_async/create_tables_async/__init__.py b/docs_src/tutorial_async/connect_async/create_tables_async/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py new file mode 100644 index 0000000000..dbc18a9d6c --- /dev/null +++ b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py @@ -0,0 +1,45 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker + +from sqlmodel import MetaData, Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def main(): + await create_db_and_tables() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/docs_src/tutorial_async/connect_async/delete_async/__init__.py b/docs_src/tutorial_async/connect_async/delete_async/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py new file mode 100644 index 0000000000..c713f6555b --- /dev/null +++ b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py @@ -0,0 +1,91 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + team_preventers = Team(name="Preventers", headquarters="Sharp Tower") + team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") + session.add(team_preventers) + session.add(team_z_force) + await session.commit() + + hero_deadpond = Hero( + name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id + ) + hero_rusty_man = Hero( + name="Rusty-Man", + secret_name="Tommy Sharp", + age=48, + team_id=team_preventers.id, + ) + hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + session.add(hero_deadpond) + session.add(hero_rusty_man) + session.add(hero_spider_boy) + await session.commit() + + await session.refresh(hero_deadpond) + await session.refresh(hero_rusty_man) + await session.refresh(hero_spider_boy) + + print("Created hero:", hero_deadpond) + print("Created hero:", hero_rusty_man) + print("Created hero:", hero_spider_boy) + + hero_spider_boy.team_id = team_preventers.id + session.add(hero_spider_boy) + await session.commit() + await session.refresh(hero_spider_boy) + print("Updated hero:", hero_spider_boy) + + hero_spider_boy.team_id = None + session.add(hero_spider_boy) + await session.commit() + await session.refresh(hero_spider_boy) + print("No longer Preventer:", hero_spider_boy) + + +async def main(): + await create_db_and_tables() + await create_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/connect_async/insert_async/__init__.py b/docs_src/tutorial_async/connect_async/insert_async/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py new file mode 100644 index 0000000000..d15d50da65 --- /dev/null +++ b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py @@ -0,0 +1,80 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker + +from sqlmodel import MetaData, Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + team_preventers = Team(name="Preventers", headquarters="Sharp Tower") + team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") + session.add(team_preventers) + session.add(team_z_force) + await session.commit() + + hero_deadpond = Hero( + name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id + ) + hero_rusty_man = Hero( + name="Rusty-Man", + secret_name="Tommy Sharp", + age=48, + team_id=team_preventers.id, + ) + hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + session.add(hero_deadpond) + session.add(hero_rusty_man) + session.add(hero_spider_boy) + await session.commit() + + await session.refresh(hero_deadpond) + await session.refresh(hero_rusty_man) + await session.refresh(hero_spider_boy) + + print("Created hero:", hero_deadpond) + print("Created hero:", hero_rusty_man) + print("Created hero:", hero_spider_boy) + + +async def main(): + await create_db_and_tables() + await create_heroes() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/docs_src/tutorial_async/connect_async/select_async/__init__.py b/docs_src/tutorial_async/connect_async/select_async/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py new file mode 100644 index 0000000000..810f622aeb --- /dev/null +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py @@ -0,0 +1,89 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + team_preventers = Team(name="Preventers", headquarters="Sharp Tower") + team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") + session.add(team_preventers) + session.add(team_z_force) + await session.commit() + + hero_deadpond = Hero( + name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id + ) + hero_rusty_man = Hero( + name="Rusty-Man", + secret_name="Tommy Sharp", + age=48, + team_id=team_preventers.id, + ) + hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + session.add(hero_deadpond) + session.add(hero_rusty_man) + session.add(hero_spider_boy) + await session.commit() + + await session.refresh(hero_deadpond) + await session.refresh(hero_rusty_man) + await session.refresh(hero_spider_boy) + + print("Created hero:", hero_deadpond) + print("Created hero:", hero_rusty_man) + print("Created hero:", hero_spider_boy) + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + statement = select(Hero, Team).where(Hero.team_id == Team.id) + results = await session.exec(statement) + for hero, team in results: + print("Hero:", hero, "Team:", team) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py new file mode 100644 index 0000000000..9cf80a796d --- /dev/null +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py @@ -0,0 +1,89 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + team_preventers = Team(name="Preventers", headquarters="Sharp Tower") + team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") + session.add(team_preventers) + session.add(team_z_force) + await session.commit() + + hero_deadpond = Hero( + name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id + ) + hero_rusty_man = Hero( + name="Rusty-Man", + secret_name="Tommy Sharp", + age=48, + team_id=team_preventers.id, + ) + hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + session.add(hero_deadpond) + session.add(hero_rusty_man) + session.add(hero_spider_boy) + await session.commit() + + await session.refresh(hero_deadpond) + await session.refresh(hero_rusty_man) + await session.refresh(hero_spider_boy) + + print("Created hero:", hero_deadpond) + print("Created hero:", hero_rusty_man) + print("Created hero:", hero_spider_boy) + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + statement = select(Hero, Team).join(Team) + results = await session.exec(statement) + for hero, team in results: + print("Hero:", hero, "Team:", team) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py new file mode 100644 index 0000000000..09f0f2b43e --- /dev/null +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py @@ -0,0 +1,89 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + team_preventers = Team(name="Preventers", headquarters="Sharp Tower") + team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") + session.add(team_preventers) + session.add(team_z_force) + await session.commit() + + hero_deadpond = Hero( + name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id + ) + hero_rusty_man = Hero( + name="Rusty-Man", + secret_name="Tommy Sharp", + age=48, + team_id=team_preventers.id, + ) + hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + session.add(hero_deadpond) + session.add(hero_rusty_man) + session.add(hero_spider_boy) + await session.commit() + + await session.refresh(hero_deadpond) + await session.refresh(hero_rusty_man) + await session.refresh(hero_spider_boy) + + print("Created hero:", hero_deadpond) + print("Created hero:", hero_rusty_man) + print("Created hero:", hero_spider_boy) + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + statement = select(Hero, Team).join(Team, isouter=True) + results = await session.exec(statement) + for hero, team in results: + print("Hero:", hero, "Team:", team) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py new file mode 100644 index 0000000000..4fe65c8499 --- /dev/null +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py @@ -0,0 +1,89 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + team_preventers = Team(name="Preventers", headquarters="Sharp Tower") + team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") + session.add(team_preventers) + session.add(team_z_force) + await session.commit() + + hero_deadpond = Hero( + name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id + ) + hero_rusty_man = Hero( + name="Rusty-Man", + secret_name="Tommy Sharp", + age=48, + team_id=team_preventers.id, + ) + hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + session.add(hero_deadpond) + session.add(hero_rusty_man) + session.add(hero_spider_boy) + await session.commit() + + await session.refresh(hero_deadpond) + await session.refresh(hero_rusty_man) + await session.refresh(hero_spider_boy) + + print("Created hero:", hero_deadpond) + print("Created hero:", hero_rusty_man) + print("Created hero:", hero_spider_boy) + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + statement = select(Hero).join(Team).where(Team.name == "Preventers") + results = await session.exec(statement) + for hero in results: + print("Preventer Hero:", hero) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py new file mode 100644 index 0000000000..63bf3201c3 --- /dev/null +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py @@ -0,0 +1,89 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + team_preventers = Team(name="Preventers", headquarters="Sharp Tower") + team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") + session.add(team_preventers) + session.add(team_z_force) + await session.commit() + + hero_deadpond = Hero( + name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id + ) + hero_rusty_man = Hero( + name="Rusty-Man", + secret_name="Tommy Sharp", + age=48, + team_id=team_preventers.id, + ) + hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + session.add(hero_deadpond) + session.add(hero_rusty_man) + session.add(hero_spider_boy) + await session.commit() + + await session.refresh(hero_deadpond) + await session.refresh(hero_rusty_man) + await session.refresh(hero_spider_boy) + + print("Created hero:", hero_deadpond) + print("Created hero:", hero_rusty_man) + print("Created hero:", hero_spider_boy) + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + statement = select(Hero, Team).join(Team).where(Team.name == "Preventers") + results = await session.exec(statement) + for hero, team in results: + print("Preventer Hero:", hero, "Team:", team) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/connect_async/update_async/__init__.py b/docs_src/tutorial_async/connect_async/update_async/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/tutorial_async/connect_async/update_async/tutorial001.py b/docs_src/tutorial_async/connect_async/update_async/tutorial001.py new file mode 100644 index 0000000000..0080340532 --- /dev/null +++ b/docs_src/tutorial_async/connect_async/update_async/tutorial001.py @@ -0,0 +1,75 @@ +from typing import Optional + +from sqlmodel import Field, Session, SQLModel, create_engine + + +class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite:///{sqlite_file_name}" + +engine = create_engine(sqlite_url, echo=True) + + +def create_db_and_tables(): + SQLModel.metadata.create_all(engine) + + +def create_heroes(): + with Session(engine) as session: + team_preventers = Team(name="Preventers", headquarters="Sharp Tower") + team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") + session.add(team_preventers) + session.add(team_z_force) + session.commit() + + hero_deadpond = Hero( + name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id + ) + hero_rusty_man = Hero( + name="Rusty-Man", + secret_name="Tommy Sharp", + age=48, + team_id=team_preventers.id, + ) + hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + session.add(hero_deadpond) + session.add(hero_rusty_man) + session.add(hero_spider_boy) + session.commit() + + session.refresh(hero_deadpond) + session.refresh(hero_rusty_man) + session.refresh(hero_spider_boy) + + print("Created hero:", hero_deadpond) + print("Created hero:", hero_rusty_man) + print("Created hero:", hero_spider_boy) + + hero_spider_boy.team_id = team_preventers.id + session.add(hero_spider_boy) + session.commit() + session.refresh(hero_spider_boy) + print("Updated hero:", hero_spider_boy) + + +def main(): + create_db_and_tables() + create_heroes() + + +if __name__ == "__main__": + main() diff --git a/docs_src/tutorial_async/select_async/__init__.py b/docs_src/tutorial_async/select_async/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/tutorial_async/select_async/annotations/en/tutorial002.md b/docs_src/tutorial_async/select_async/annotations/en/tutorial002.md new file mode 100644 index 0000000000..2570b542c4 --- /dev/null +++ b/docs_src/tutorial_async/select_async/annotations/en/tutorial002.md @@ -0,0 +1,63 @@ +1. Import from `sqlmodel` everything we will use, including the new `select()` function. + +2. Create the `Hero` class model, representing the `hero` table. + +3. Create the **engine**, we should use a single one shared by all the application code, and that's what we are doing here. + +4. Create all the tables for the models registered in `SQLModel.metadata`. + + This also creates the database if it doesn't exist already. + +5. Create each one of the `Hero` objects. + + You might not have this in your version if you had already created the data in the database. + +6. Create a new **session** and use it to `add` the heroes to the database, and then `commit` the changes. + +7. Create a new **session** to query data. + + !!! tip + Notice that this is a new **session** independent from the one in the other function above. + + But it still uses the same **engine**. We still have one engine for the whole application. + +8. Use the `select()` function to create a statement selecting all the `Hero` objects. + + This selects all the rows in the `hero` table. + +9. Use `session.exec(statement)` to make the **session** use the **engine** to execute the internal SQL statement. + + This will go to the database, execute that SQL, and get the results back. + + It returns a special iterable object that we put in the variable `results`. + + This generates the output: + + ``` + INFO Engine BEGIN (implicit) + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero + INFO Engine [no key 0.00032s] () + ``` + +10. Iterate for each `Hero` object in the `results`. + +11. Print each `hero`. + + The 3 iterations in the `for` loop will generate this output: + + ``` + id=1 name='Deadpond' age=None secret_name='Dive Wilson' + id=2 name='Spider-Boy' age=None secret_name='Pedro Parqueador' + id=3 name='Rusty-Man' age=48 secret_name='Tommy Sharp' + ``` + +12. At this point, after the `with` block, the **session** is closed. + + This generates the output: + + ``` + INFO Engine ROLLBACK + ``` + +13. Add this function `select_heroes()` to the `main()` function so that it is called when we run this program from the command line. diff --git a/docs_src/tutorial_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/select_async/tutorial001_async.py new file mode 100644 index 0000000000..5034b997b3 --- /dev/null +++ b/docs_src/tutorial_async/select_async/tutorial001_async.py @@ -0,0 +1,62 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str + secret_name: str + age: Optional[int] = None + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") + hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + session.add(hero_1) + session.add(hero_2) + session.add(hero_3) + + await session.commit() + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + statement = select(Hero) + results = await session.exec(statement) + for hero in results: + print(hero) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/select_async/tutorial002_async.py new file mode 100644 index 0000000000..598abee85f --- /dev/null +++ b/docs_src/tutorial_async/select_async/tutorial002_async.py @@ -0,0 +1,62 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession # (1) + + +class Hero(SQLModel, table=True): # (2) + id: Optional[int] = Field(default=None, primary_key=True) + name: str + secret_name: str + age: Optional[int] = None + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) # (3) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) # (4) + + +async def create_heroes(): + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (5) + hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: # (6) + session.add(hero_1) + session.add(hero_2) + session.add(hero_3) + + await session.commit() + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: # (7) + statement = select(Hero) # (8) + results = await session.exec(statement) # (9) + for hero in results: # (10) + print(hero) # (11) + # (12) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() # (13) + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/select_async/tutorial003_async.py new file mode 100644 index 0000000000..0082cf92b7 --- /dev/null +++ b/docs_src/tutorial_async/select_async/tutorial003_async.py @@ -0,0 +1,61 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str + secret_name: str + age: Optional[int] = None + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") + hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + session.add(hero_1) + session.add(hero_2) + session.add(hero_3) + + await session.commit() + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + statement = select(Hero) + results = await session.exec(statement) + heroes = results.all() + print(heroes) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/docs_src/tutorial_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/select_async/tutorial004_async.py new file mode 100644 index 0000000000..af55f71005 --- /dev/null +++ b/docs_src/tutorial_async/select_async/tutorial004_async.py @@ -0,0 +1,62 @@ +import asyncio +from typing import Optional + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str + secret_name: str + age: Optional[int] = None + + +sqlite_file_name = "database.db" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" + +engine = create_async_engine(sqlite_url, echo=True) + + +async def create_db_and_tables(): + meta = SQLModel.metadata + + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) + + +async def create_heroes(): + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") + hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") + hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + session.add(hero_1) + session.add(hero_2) + session.add(hero_3) + + await session.commit() + + +async def select_heroes(): + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: + # TODO: in async, this does not work `await session.exec(select(Hero)).all()` + # heroes = await session.exec(select(Hero)).all() + results = await session.exec(select(Hero)) + heroes = results.all() + print(heroes) + + +async def main(): + await create_db_and_tables() + await create_heroes() + await select_heroes() + + +if __name__ == "__main__": + asyncio.run(main) diff --git a/tests/test_async_tutorial/test_async_connect/__init__.py b/tests/test_async_tutorial/test_async_connect/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/__init__.py b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py new file mode 100644 index 0000000000..d94a365093 --- /dev/null +++ b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py @@ -0,0 +1,42 @@ +import pytest +from sqlalchemy import inspect +from sqlalchemy.engine.reflection import Inspector +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + + +@pytest.mark.asyncio +async def test_async_tutorial001(): + from docs_src.tutorial_async.connect_async.create_tables_async import ( + tutorial001_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + meta = SQLModel.metadata + async_session = sessionmaker( + mod.engine, expire_on_commit=False, class_=AsyncSession + ) + + async with mod.engine.begin() as conn1: + # await conn1.run_sync(meta.drop_all) + await conn1.run_sync(meta.create_all) + await mod.main() + + # async with async_session() as session1: + # async with session1.begin(): + # await session1.run_sync(meta.create_all) + # await session1.run_sync(mod.main()) + + # async with mod.engine.begin() as conn1: + # await conn1.run_sync(mod.main()) + # await conn1.run_sync(meta.create_all) + # mod.main() + + # insp: Inspector = inspect(mod.engine) + # assert insp.has_table(str(mod.Hero.__tablename__)) + # assert insp.has_table(str(mod.Team.__tablename__)) + + assert True diff --git a/tests/test_async_tutorial/test_async_connect/test_async_delete/__init__.py b/tests/test_async_tutorial/test_async_connect/test_async_delete/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py new file mode 100644 index 0000000000..30ba65239d --- /dev/null +++ b/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py @@ -0,0 +1,79 @@ +import pytest +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + +from tests.conftest import get_testing_print_function + +expected_calls = [ + [ + "Created hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + ], + [ + "Created hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + ], + [ + "Created hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + ], + [ + "Updated hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": 1, + "name": "Spider-Boy", + }, + ], + [ + "No longer Preventer:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + ], +] + + +@pytest.mark.asyncio() +async def test_tutorial_async(clear_sqlmodel): + from docs_src.tutorial_async.connect_async.delete_async import ( + tutorial001_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + assert calls == expected_calls diff --git a/tests/test_async_tutorial/test_async_connect/test_async_insert/__init__.py b/tests/test_async_tutorial/test_async_connect/test_async_insert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py new file mode 100644 index 0000000000..a059cf9417 --- /dev/null +++ b/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py @@ -0,0 +1,59 @@ +import pytest +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + +from tests.conftest import get_testing_print_function + +expected_calls = [ + [ + "Created hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + ], + [ + "Created hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + ], + [ + "Created hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + ], +] + + +@pytest.mark.asyncio() +async def test_async_tutorial001(clear_sqlmodel): + from docs_src.tutorial_async.connect_async.insert_async import ( + tutorial001_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + assert calls == expected_calls diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/__init__.py b/tests/test_async_tutorial/test_async_connect/test_async_select/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py new file mode 100644 index 0000000000..535f187625 --- /dev/null +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py @@ -0,0 +1,100 @@ +import pytest +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + +from tests.conftest import get_testing_print_function + +expected_calls = [ + [ + "Created hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + ], + [ + "Created hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + ], + [ + "Created hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + ], + [ + "Hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + "Team:", + {"id": 2, "name": "Z-Force", "headquarters": "Sister Margaret’s Bar"}, + ], + [ + "Hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + "Team:", + {"id": 1, "name": "Preventers", "headquarters": "Sharp Tower"}, + ], +] + + +@pytest.mark.asyncio() +async def test_tutorial001(clear_sqlmodel): + from docs_src.tutorial_async.connect_async.select_async import ( + tutorial001_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + assert calls == expected_calls + + +@pytest.mark.asyncio() +async def test_tutorial002(clear_sqlmodel): + from docs_src.tutorial_async.connect_async.select_async import ( + tutorial002_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + assert calls == expected_calls diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py new file mode 100644 index 0000000000..10e20e7e9e --- /dev/null +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py @@ -0,0 +1,95 @@ +import pytest +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + +from tests.conftest import get_testing_print_function + +expected_calls = [ + [ + "Created hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + ], + [ + "Created hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + ], + [ + "Created hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + ], + [ + "Hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + "Team:", + {"id": 2, "name": "Z-Force", "headquarters": "Sister Margaret’s Bar"}, + ], + [ + "Hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + "Team:", + {"id": 1, "name": "Preventers", "headquarters": "Sharp Tower"}, + ], + [ + "Hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + "Team:", + None, + ], +] + + +@pytest.mark.asyncio() +async def test_tutorial(clear_sqlmodel): + from docs_src.tutorial_async.connect_async.select_async import ( + tutorial003_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + assert calls == expected_calls diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py new file mode 100644 index 0000000000..e401a6d9c2 --- /dev/null +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py @@ -0,0 +1,69 @@ +import pytest +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + +from tests.conftest import get_testing_print_function + +expected_calls = [ + [ + "Created hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + ], + [ + "Created hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + ], + [ + "Created hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + ], + [ + "Preventer Hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + ], +] + + +@pytest.mark.asyncio() +async def test_tutorial(clear_sqlmodel): + from docs_src.tutorial_async.connect_async.select_async import ( + tutorial004_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + assert calls == expected_calls diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py new file mode 100644 index 0000000000..9aa69983aa --- /dev/null +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py @@ -0,0 +1,71 @@ +import pytest +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + +from tests.conftest import get_testing_print_function + +expected_calls = [ + [ + "Created hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + ], + [ + "Created hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + ], + [ + "Created hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + ], + [ + "Preventer Hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + "Team:", + {"id": 1, "name": "Preventers", "headquarters": "Sharp Tower"}, + ], +] + + +@pytest.mark.asyncio() +async def test_tutorial(clear_sqlmodel): + from docs_src.tutorial_async.connect_async.select_async import ( + tutorial005_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + assert calls == expected_calls diff --git a/tests/test_async_tutorial/test_async_select/__init__.py b/tests/test_async_tutorial/test_async_select/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py b/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py new file mode 100644 index 0000000000..e932ecad2b --- /dev/null +++ b/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py @@ -0,0 +1,62 @@ +import pytest +from typing import Any, Dict, List, Union +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import MetaData, Session, SQLModel, create_engine, select +from sqlmodel.ext.asyncio.session import AsyncSession +from sqlmodel import create_engine + +from tests.conftest import get_testing_print_function + + +def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]): + assert calls[0][0] == { + "name": "Deadpond", + "secret_name": "Dive Wilson", + "age": None, + "id": 1, + } + assert calls[1][0] == { + "name": "Spider-Boy", + "secret_name": "Pedro Parqueador", + "age": None, + "id": 2, + } + assert calls[2][0] == { + "name": "Rusty-Man", + "secret_name": "Tommy Sharp", + "age": 48, + "id": 3, + } + + +@pytest.mark.asyncio +async def test_tutorial_async_001(clear_sqlmodel): + from docs_src.tutorial_async.select_async import tutorial001_async as mod + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + check_calls(calls) + + +@pytest.mark.asyncio +async def test_tutorial_async_002(clear_sqlmodel): + from docs_src.tutorial_async.select_async import tutorial002_async as mod + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + check_calls(calls) diff --git a/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py b/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py new file mode 100644 index 0000000000..da9cba0fb9 --- /dev/null +++ b/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py @@ -0,0 +1,65 @@ +import pytest +from typing import Any, Dict, List, Union +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import MetaData, Session, SQLModel, create_engine, select +from sqlmodel.ext.asyncio.session import AsyncSession +from sqlmodel import create_engine + +from tests.conftest import get_testing_print_function + + +def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]): + assert calls[0][0] == [ + { + "name": "Deadpond", + "secret_name": "Dive Wilson", + "age": None, + "id": 1, + }, + { + "name": "Spider-Boy", + "secret_name": "Pedro Parqueador", + "age": None, + "id": 2, + }, + { + "name": "Rusty-Man", + "secret_name": "Tommy Sharp", + "age": 48, + "id": 3, + }, + ] + + +@pytest.mark.asyncio +async def test_tutorial_003(clear_sqlmodel): + from docs_src.tutorial_async.select_async import tutorial003_async as mod + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + check_calls(calls) + + +@pytest.mark.asyncio +async def test_tutorial_004(clear_sqlmodel): + from docs_src.tutorial_async.select_async import tutorial004_async as mod + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + check_calls(calls) From 886b962435f24eb47ea67cac711686cbf0b4c303 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Sat, 15 Oct 2022 00:30:29 +1300 Subject: [PATCH 02/13] fix: mypy static typing failures , FieldInfo use https://pydantic-docs.helpmanual.io/usage/schema/#typingannotated-fields --- .../create_tables_async/tutorial001_async.py | 21 +++--- .../delete_async/tutorial001_async.py | 20 +++--- .../insert_async/tutorial001_async.py | 21 +++--- .../select_async/tutorial001_async.py | 20 +++--- .../select_async/tutorial002_async.py | 20 +++--- .../select_async/tutorial003_async.py | 20 +++--- .../select_async/tutorial004_async.py | 20 +++--- .../select_async/tutorial005_async.py | 20 +++--- .../connect_async/update_async/tutorial001.py | 64 +++++++++++-------- 9 files changed, 135 insertions(+), 91 deletions(-) diff --git a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py index dbc18a9d6c..4248a6d47b 100644 --- a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py @@ -1,26 +1,29 @@ import asyncio -from typing import Optional +from typing import Optional, Union, Any +from typing import Annotated from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker - -from sqlmodel import MetaData, Field, Session, SQLModel, select +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" diff --git a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py index c713f6555b..6c8355f230 100644 --- a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py @@ -1,25 +1,29 @@ import asyncio -from typing import Optional +from typing import Optional, Union, Any +from typing import Annotated from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" @@ -88,4 +92,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py index d15d50da65..cd32f75a4b 100644 --- a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py @@ -1,26 +1,29 @@ import asyncio -from typing import Optional +from typing import Optional, Union, Any +from typing import Annotated from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker - -from sqlmodel import MetaData, Field, Session, SQLModel, select +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py index 810f622aeb..1e486d6419 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py @@ -1,25 +1,29 @@ import asyncio -from typing import Optional +from typing import Optional, Union, Any +from typing import Annotated from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" @@ -86,4 +90,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py index 9cf80a796d..7039f27cbe 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py @@ -1,25 +1,29 @@ import asyncio -from typing import Optional +from typing import Optional, Union, Any +from typing import Annotated from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" @@ -86,4 +90,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py index 09f0f2b43e..24f7349b48 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py @@ -1,25 +1,29 @@ import asyncio -from typing import Optional +from typing import Optional, Union, Any +from typing import Annotated from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" @@ -86,4 +90,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py index 4fe65c8499..f7214214e4 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py @@ -1,25 +1,29 @@ import asyncio -from typing import Optional +from typing import Optional, Union, Any +from typing import Annotated from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" @@ -86,4 +90,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py index 63bf3201c3..a68c4df837 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py @@ -1,25 +1,29 @@ import asyncio -from typing import Optional +from typing import Optional, Union, Any +from typing import Annotated from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" @@ -86,4 +90,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/connect_async/update_async/tutorial001.py b/docs_src/tutorial_async/connect_async/update_async/tutorial001.py index 0080340532..1a17324e92 100644 --- a/docs_src/tutorial_async/connect_async/update_async/tutorial001.py +++ b/docs_src/tutorial_async/connect_async/update_async/tutorial001.py @@ -1,40 +1,54 @@ -from typing import Optional +import asyncio +from typing import Optional, Union, Any +from typing import Annotated -from sqlmodel import Field, Session, SQLModel, create_engine +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Field, Session, SQLModel, select +from sqlmodel.main import FieldInfo +from sqlmodel.ext.asyncio.session import AsyncSession class Team(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] headquarters: str class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str = Field(index=True) + id: Annotated[int, Field(primary_key=True)] + name: Annotated[str, Field(index=True)] secret_name: str - age: Optional[int] = Field(default=None, index=True) + age: Annotated[Optional[int], Field(default_factory=lambda: None, index=True)] - team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team_id: Annotated[ + Optional[int], Field(default_factory=lambda: None, foreign_key="team.id") + ] sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" +sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}" -engine = create_engine(sqlite_url, echo=True) +engine = create_async_engine(sqlite_url, echo=True) -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) +async def create_db_and_tables(): + meta = SQLModel.metadata + async with engine.begin() as conn: + await conn.run_sync(meta.drop_all) + await conn.run_sync(meta.create_all) -def create_heroes(): - with Session(engine) as session: + +async def create_heroes(): + + async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) + async with async_session() as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) session.add(team_z_force) - session.commit() + await session.commit() hero_deadpond = Hero( name="Deadpond", secret_name="Dive Wilson", team_id=team_z_force.id @@ -49,11 +63,11 @@ def create_heroes(): session.add(hero_deadpond) session.add(hero_rusty_man) session.add(hero_spider_boy) - session.commit() + await session.commit() - session.refresh(hero_deadpond) - session.refresh(hero_rusty_man) - session.refresh(hero_spider_boy) + await session.refresh(hero_deadpond) + await session.refresh(hero_rusty_man) + await session.refresh(hero_spider_boy) print("Created hero:", hero_deadpond) print("Created hero:", hero_rusty_man) @@ -61,15 +75,15 @@ def create_heroes(): hero_spider_boy.team_id = team_preventers.id session.add(hero_spider_boy) - session.commit() - session.refresh(hero_spider_boy) + await session.commit() + await session.refresh(hero_spider_boy) print("Updated hero:", hero_spider_boy) -def main(): - create_db_and_tables() - create_heroes() +async def main(): + await create_db_and_tables() + await create_heroes() if __name__ == "__main__": - main() + asyncio.run(main()) From bca1a7b99f882a04966da17075c5b57a598b084f Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Sat, 15 Oct 2022 07:41:32 +1300 Subject: [PATCH 03/13] test: add missing async test `update` refactor: mypy issues with annotations refactor: simplify async session using SQLmodel to pass mypy use typdef Annotation see https://pydantic-docs.helpmanual.io/usage/schema/#typingannotated-fields --- .../{tutorial001.py => tutorial001_async.py} | 0 .../select_async/tutorial001_async.py | 16 ++--- .../select_async/tutorial002_async.py | 16 ++--- .../select_async/tutorial003_async.py | 16 ++--- .../select_async/tutorial004_async.py | 16 ++--- .../test_async_update/__init__.py | 0 .../test_async_tutorial001.py | 69 +++++++++++++++++++ 7 files changed, 97 insertions(+), 36 deletions(-) rename docs_src/tutorial_async/connect_async/update_async/{tutorial001.py => tutorial001_async.py} (100%) create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_update/__init__.py create mode 100644 tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py diff --git a/docs_src/tutorial_async/connect_async/update_async/tutorial001.py b/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py similarity index 100% rename from docs_src/tutorial_async/connect_async/update_async/tutorial001.py rename to docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py diff --git a/docs_src/tutorial_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/select_async/tutorial001_async.py index 5034b997b3..19f4bfdce4 100644 --- a/docs_src/tutorial_async/select_async/tutorial001_async.py +++ b/docs_src/tutorial_async/select_async/tutorial001_async.py @@ -1,14 +1,14 @@ import asyncio -from typing import Optional +from typing import Annotated, Optional from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select + +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) + id: Annotated[int, Field(primary_key=True)] name: str secret_name: str age: Optional[int] = None @@ -34,8 +34,7 @@ async def create_heroes(): hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: session.add(hero_1) session.add(hero_2) session.add(hero_3) @@ -44,8 +43,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: statement = select(Hero) results = await session.exec(statement) for hero in results: @@ -59,4 +57,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/select_async/tutorial002_async.py index 598abee85f..98b2556406 100644 --- a/docs_src/tutorial_async/select_async/tutorial002_async.py +++ b/docs_src/tutorial_async/select_async/tutorial002_async.py @@ -1,14 +1,14 @@ import asyncio -from typing import Optional +from typing import Annotated, Optional from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select + +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession # (1) class Hero(SQLModel, table=True): # (2) - id: Optional[int] = Field(default=None, primary_key=True) + id: Annotated[int, Field(primary_key=True)] name: str secret_name: str age: Optional[int] = None @@ -33,8 +33,7 @@ async def create_heroes(): hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: # (6) + async with AsyncSession(engine) as session: # (6) session.add(hero_1) session.add(hero_2) session.add(hero_3) @@ -43,8 +42,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: # (7) + async with AsyncSession(engine) as session: # (7) statement = select(Hero) # (8) results = await session.exec(statement) # (9) for hero in results: # (10) @@ -59,4 +57,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/select_async/tutorial003_async.py index 0082cf92b7..227f790591 100644 --- a/docs_src/tutorial_async/select_async/tutorial003_async.py +++ b/docs_src/tutorial_async/select_async/tutorial003_async.py @@ -1,14 +1,14 @@ import asyncio -from typing import Optional +from typing import Annotated, Optional from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select + +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) + id: Annotated[int, Field(primary_key=True)] name: str secret_name: str age: Optional[int] = None @@ -33,8 +33,7 @@ async def create_heroes(): hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: session.add(hero_1) session.add(hero_2) session.add(hero_3) @@ -43,8 +42,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: statement = select(Hero) results = await session.exec(statement) heroes = results.all() @@ -58,4 +56,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/docs_src/tutorial_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/select_async/tutorial004_async.py index af55f71005..3c21681705 100644 --- a/docs_src/tutorial_async/select_async/tutorial004_async.py +++ b/docs_src/tutorial_async/select_async/tutorial004_async.py @@ -1,14 +1,14 @@ import asyncio -from typing import Optional +from typing import Annotated, Optional from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select + +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) + id: Annotated[int, Field(primary_key=True)] name: str secret_name: str age: Optional[int] = None @@ -33,8 +33,7 @@ async def create_heroes(): hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: session.add(hero_1) session.add(hero_2) session.add(hero_3) @@ -43,8 +42,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: # TODO: in async, this does not work `await session.exec(select(Hero)).all()` # heroes = await session.exec(select(Hero)).all() results = await session.exec(select(Hero)) @@ -59,4 +57,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main) + asyncio.run(main()) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_update/__init__.py b/tests/test_async_tutorial/test_async_connect/test_async_update/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py new file mode 100644 index 0000000000..c893a349c6 --- /dev/null +++ b/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py @@ -0,0 +1,69 @@ +import pytest +from unittest.mock import patch + +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.orm import sessionmaker +from sqlmodel import Session, SQLModel, select +from sqlmodel.ext.asyncio.session import AsyncSession + +from tests.conftest import get_testing_print_function + +expected_calls = [ + [ + "Created hero:", + { + "age": None, + "id": 1, + "secret_name": "Dive Wilson", + "team_id": 2, + "name": "Deadpond", + }, + ], + [ + "Created hero:", + { + "age": 48, + "id": 2, + "secret_name": "Tommy Sharp", + "team_id": 1, + "name": "Rusty-Man", + }, + ], + [ + "Created hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": None, + "name": "Spider-Boy", + }, + ], + [ + "Updated hero:", + { + "age": None, + "id": 3, + "secret_name": "Pedro Parqueador", + "team_id": 1, + "name": "Spider-Boy", + }, + ], +] + + +@pytest.mark.asyncio() +async def test_tutorial(clear_sqlmodel): + from docs_src.tutorial_async.connect_async.update_async import ( + tutorial001_async as mod, + ) + + mod.sqlite_url = "sqlite+aiosqlite://" + mod.engine = create_async_engine(mod.sqlite_url) + calls = [] + + new_print = get_testing_print_function(calls) + + with patch("builtins.print", new=new_print): + await mod.main() + assert calls == expected_calls From 6dec3fe2be0e8da9d805ef877c3ea6de8faf5957 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Sat, 15 Oct 2022 11:42:24 +1300 Subject: [PATCH 04/13] refactor: simplify imports doc: TODO depend on PR435 refactor: simply session start --- .../create_tables_async/tutorial001_async.py | 11 ++++++----- .../delete_async/tutorial001_async.py | 14 +++++++------- .../insert_async/tutorial001_async.py | 14 +++++++------- .../select_async/tutorial001_async.py | 17 ++++++++--------- .../select_async/tutorial002_async.py | 17 ++++++++--------- .../select_async/tutorial003_async.py | 17 ++++++++--------- .../select_async/tutorial004_async.py | 17 ++++++++--------- .../select_async/tutorial005_async.py | 17 ++++++++--------- .../update_async/tutorial001_async.py | 14 +++++++------- .../select_async/tutorial001_async.py | 5 ++++- .../select_async/tutorial002_async.py | 5 ++++- .../select_async/tutorial003_async.py | 5 ++++- .../select_async/tutorial004_async.py | 5 ++++- 13 files changed, 83 insertions(+), 75 deletions(-) diff --git a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py index 4248a6d47b..bbbf566867 100644 --- a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession diff --git a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py index 6c8355f230..880425c27d 100644 --- a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession @@ -42,8 +43,7 @@ async def create_db_and_tables(): async def create_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) diff --git a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py index cd32f75a4b..74de5b118f 100644 --- a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession @@ -42,8 +43,7 @@ async def create_db_and_tables(): async def create_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py index 1e486d6419..94ac0ddcad 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession @@ -42,8 +43,7 @@ async def create_db_and_tables(): async def create_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) @@ -75,8 +75,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: statement = select(Hero, Team).where(Hero.team_id == Team.id) results = await session.exec(statement) for hero, team in results: diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py index 7039f27cbe..bbd5bc120c 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession @@ -42,8 +43,7 @@ async def create_db_and_tables(): async def create_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) @@ -75,8 +75,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: statement = select(Hero, Team).join(Team) results = await session.exec(statement) for hero, team in results: diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py index 24f7349b48..9354bd871e 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession @@ -42,8 +43,7 @@ async def create_db_and_tables(): async def create_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) @@ -75,8 +75,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: statement = select(Hero, Team).join(Team, isouter=True) results = await session.exec(statement) for hero, team in results: diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py index f7214214e4..f2d75b2c55 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession @@ -42,8 +43,7 @@ async def create_db_and_tables(): async def create_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) @@ -75,8 +75,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: statement = select(Hero).join(Team).where(Team.name == "Preventers") results = await session.exec(statement) for hero in results: diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py index a68c4df837..4aefcc1822 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession @@ -42,8 +43,7 @@ async def create_db_and_tables(): async def create_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) @@ -75,8 +75,7 @@ async def create_heroes(): async def select_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine) as session: statement = select(Hero, Team).join(Team).where(Team.name == "Preventers") results = await session.exec(statement) for hero, team in results: diff --git a/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py index 1a17324e92..1f60d8d344 100644 --- a/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional, Union, Any -from typing import Annotated +from typing import Annotated, Optional + +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, select -from sqlmodel.main import FieldInfo +from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession @@ -42,8 +43,7 @@ async def create_db_and_tables(): async def create_heroes(): - async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) - async with async_session() as session: + async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar") session.add(team_preventers) diff --git a/docs_src/tutorial_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/select_async/tutorial001_async.py index 19f4bfdce4..c67428c190 100644 --- a/docs_src/tutorial_async/select_async/tutorial001_async.py +++ b/docs_src/tutorial_async/select_async/tutorial001_async.py @@ -1,8 +1,11 @@ import asyncio from typing import Annotated, Optional -from sqlalchemy.ext.asyncio import create_async_engine +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select +from sqlalchemy.ext.asyncio import create_async_engine from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession diff --git a/docs_src/tutorial_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/select_async/tutorial002_async.py index 98b2556406..30329df963 100644 --- a/docs_src/tutorial_async/select_async/tutorial002_async.py +++ b/docs_src/tutorial_async/select_async/tutorial002_async.py @@ -1,8 +1,11 @@ import asyncio from typing import Annotated, Optional -from sqlalchemy.ext.asyncio import create_async_engine +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select +from sqlalchemy.ext.asyncio import create_async_engine from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession # (1) diff --git a/docs_src/tutorial_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/select_async/tutorial003_async.py index 227f790591..d0762dec1d 100644 --- a/docs_src/tutorial_async/select_async/tutorial003_async.py +++ b/docs_src/tutorial_async/select_async/tutorial003_async.py @@ -1,8 +1,11 @@ import asyncio from typing import Annotated, Optional -from sqlalchemy.ext.asyncio import create_async_engine +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select +from sqlalchemy.ext.asyncio import create_async_engine from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession diff --git a/docs_src/tutorial_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/select_async/tutorial004_async.py index 3c21681705..928cebd94b 100644 --- a/docs_src/tutorial_async/select_async/tutorial004_async.py +++ b/docs_src/tutorial_async/select_async/tutorial004_async.py @@ -1,8 +1,11 @@ import asyncio from typing import Annotated, Optional -from sqlalchemy.ext.asyncio import create_async_engine +# TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted +# TODO replace following 3 lines with: +# ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select +from sqlalchemy.ext.asyncio import create_async_engine from sqlmodel import Field, SQLModel, select from sqlmodel.ext.asyncio.session import AsyncSession From 14bb1b271df7c85bcbb5450f28f1faed052ea286 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Sat, 15 Oct 2022 21:49:51 +1300 Subject: [PATCH 05/13] refactor: fix function return types for mypy --- docs_src/tutorial_async/.python-version | 1 + .../create_tables_async/tutorial001_async.py | 4 ++-- .../connect_async/delete_async/tutorial001_async.py | 6 +++--- .../connect_async/insert_async/tutorial001_async.py | 6 +++--- .../connect_async/select_async/tutorial001_async.py | 8 ++++---- .../connect_async/select_async/tutorial002_async.py | 8 ++++---- .../connect_async/select_async/tutorial003_async.py | 8 ++++---- .../connect_async/select_async/tutorial004_async.py | 8 ++++---- .../connect_async/select_async/tutorial005_async.py | 8 ++++---- .../connect_async/update_async/tutorial001_async.py | 6 +++--- docs_src/tutorial_async/select_async/tutorial001_async.py | 8 ++++---- docs_src/tutorial_async/select_async/tutorial002_async.py | 8 ++++---- docs_src/tutorial_async/select_async/tutorial003_async.py | 8 ++++---- docs_src/tutorial_async/select_async/tutorial004_async.py | 8 ++++---- 14 files changed, 48 insertions(+), 47 deletions(-) create mode 100644 docs_src/tutorial_async/.python-version diff --git a/docs_src/tutorial_async/.python-version b/docs_src/tutorial_async/.python-version new file mode 100644 index 0000000000..55689195cb --- /dev/null +++ b/docs_src/tutorial_async/.python-version @@ -0,0 +1 @@ +3.10.7 diff --git a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py index bbbf566867..f63facbf49 100644 --- a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def main(): +async def main() -> None: await create_db_and_tables() diff --git a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py index 880425c27d..6e123f7002 100644 --- a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") @@ -86,7 +86,7 @@ async def create_heroes(): print("No longer Preventer:", hero_spider_boy) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() diff --git a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py index 74de5b118f..8958c0c21e 100644 --- a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") @@ -74,7 +74,7 @@ async def create_heroes(): print("Created hero:", hero_spider_boy) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py index 94ac0ddcad..fdf028643b 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") @@ -74,7 +74,7 @@ async def create_heroes(): print("Created hero:", hero_spider_boy) -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine) as session: statement = select(Hero, Team).where(Hero.team_id == Team.id) results = await session.exec(statement) @@ -82,7 +82,7 @@ async def select_heroes(): print("Hero:", hero, "Team:", team) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py index bbd5bc120c..1d4828b5d7 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") @@ -74,7 +74,7 @@ async def create_heroes(): print("Created hero:", hero_spider_boy) -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine) as session: statement = select(Hero, Team).join(Team) results = await session.exec(statement) @@ -82,7 +82,7 @@ async def select_heroes(): print("Hero:", hero, "Team:", team) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py index 9354bd871e..7642c595f3 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") @@ -74,7 +74,7 @@ async def create_heroes(): print("Created hero:", hero_spider_boy) -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine) as session: statement = select(Hero, Team).join(Team, isouter=True) results = await session.exec(statement) @@ -82,7 +82,7 @@ async def select_heroes(): print("Hero:", hero, "Team:", team) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py index f2d75b2c55..666f265076 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") @@ -74,7 +74,7 @@ async def create_heroes(): print("Created hero:", hero_spider_boy) -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: statement = select(Hero).join(Team).where(Team.name == "Preventers") results = await session.exec(statement) @@ -82,7 +82,7 @@ async def select_heroes(): print("Preventer Hero:", hero) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py index 4aefcc1822..fcd04ee2f5 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") @@ -74,7 +74,7 @@ async def create_heroes(): print("Created hero:", hero_spider_boy) -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine) as session: statement = select(Hero, Team).join(Team).where(Team.name == "Preventers") results = await session.exec(statement) @@ -82,7 +82,7 @@ async def select_heroes(): print("Preventer Hero:", hero, "Team:", team) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() diff --git a/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py index 1f60d8d344..e7b41de791 100644 --- a/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py @@ -33,7 +33,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -41,7 +41,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: async with AsyncSession(engine, expire_on_commit=False) as session: team_preventers = Team(name="Preventers", headquarters="Sharp Tower") @@ -80,7 +80,7 @@ async def create_heroes(): print("Updated hero:", hero_spider_boy) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() diff --git a/docs_src/tutorial_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/select_async/tutorial001_async.py index c67428c190..c0ec6d1606 100644 --- a/docs_src/tutorial_async/select_async/tutorial001_async.py +++ b/docs_src/tutorial_async/select_async/tutorial001_async.py @@ -23,7 +23,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -31,7 +31,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") @@ -45,7 +45,7 @@ async def create_heroes(): await session.commit() -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine) as session: statement = select(Hero) results = await session.exec(statement) @@ -53,7 +53,7 @@ async def select_heroes(): print(hero) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() diff --git a/docs_src/tutorial_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/select_async/tutorial002_async.py index 30329df963..4dbf1c8209 100644 --- a/docs_src/tutorial_async/select_async/tutorial002_async.py +++ b/docs_src/tutorial_async/select_async/tutorial002_async.py @@ -23,7 +23,7 @@ class Hero(SQLModel, table=True): # (2) engine = create_async_engine(sqlite_url, echo=True) # (3) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -31,7 +31,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) # (4) -async def create_heroes(): +async def create_heroes() -> None: hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (5) hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) @@ -44,7 +44,7 @@ async def create_heroes(): await session.commit() -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine) as session: # (7) statement = select(Hero) # (8) results = await session.exec(statement) # (9) @@ -53,7 +53,7 @@ async def select_heroes(): # (12) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() # (13) diff --git a/docs_src/tutorial_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/select_async/tutorial003_async.py index d0762dec1d..9971a6c42f 100644 --- a/docs_src/tutorial_async/select_async/tutorial003_async.py +++ b/docs_src/tutorial_async/select_async/tutorial003_async.py @@ -23,7 +23,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -31,7 +31,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) @@ -44,7 +44,7 @@ async def create_heroes(): await session.commit() -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine) as session: statement = select(Hero) results = await session.exec(statement) @@ -52,7 +52,7 @@ async def select_heroes(): print(heroes) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() diff --git a/docs_src/tutorial_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/select_async/tutorial004_async.py index 928cebd94b..8407ae94c4 100644 --- a/docs_src/tutorial_async/select_async/tutorial004_async.py +++ b/docs_src/tutorial_async/select_async/tutorial004_async.py @@ -23,7 +23,7 @@ class Hero(SQLModel, table=True): engine = create_async_engine(sqlite_url, echo=True) -async def create_db_and_tables(): +async def create_db_and_tables() -> None: meta = SQLModel.metadata async with engine.begin() as conn: @@ -31,7 +31,7 @@ async def create_db_and_tables(): await conn.run_sync(meta.create_all) -async def create_heroes(): +async def create_heroes() -> None: hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) @@ -44,7 +44,7 @@ async def create_heroes(): await session.commit() -async def select_heroes(): +async def select_heroes() -> None: async with AsyncSession(engine) as session: # TODO: in async, this does not work `await session.exec(select(Hero)).all()` # heroes = await session.exec(select(Hero)).all() @@ -53,7 +53,7 @@ async def select_heroes(): print(heroes) -async def main(): +async def main() -> None: await create_db_and_tables() await create_heroes() await select_heroes() From 9e19608736cd6c78074ee527e333ad4095699842 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Sun, 16 Oct 2022 09:30:55 +1300 Subject: [PATCH 06/13] test: workaround for async inspect --- .../test_async_tutorial001.py | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py index d94a365093..daeba2bbaa 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py @@ -8,35 +8,40 @@ @pytest.mark.asyncio -async def test_async_tutorial001(): +async def test_async_tutorial001()->None: from docs_src.tutorial_async.connect_async.create_tables_async import ( tutorial001_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - meta = SQLModel.metadata - async_session = sessionmaker( - mod.engine, expire_on_commit=False, class_=AsyncSession - ) - async with mod.engine.begin() as conn1: - # await conn1.run_sync(meta.drop_all) - await conn1.run_sync(meta.create_all) + await mod.main() - # async with async_session() as session1: - # async with session1.begin(): - # await session1.run_sync(meta.create_all) - # await session1.run_sync(mod.main()) - # async with mod.engine.begin() as conn1: - # await conn1.run_sync(mod.main()) - # await conn1.run_sync(meta.create_all) - # mod.main() + + # Following code lines are for sync implementation , see following note regarding async + # https://docs.sqlalchemy.org/en/14/errors.html#error-xd3s # insp: Inspector = inspect(mod.engine) # assert insp.has_table(str(mod.Hero.__tablename__)) # assert insp.has_table(str(mod.Team.__tablename__)) - assert True + # following is recommended workaround + async with mod.engine.connect() as conn: + tables = await conn.run_sync( + lambda sync_conn: inspect(sync_conn).get_table_names() + ) + assert str(mod.Team.__tablename__) in tables + assert str(mod.Hero.__tablename__) in tables + + # TODO; work out how to call insp.has_tables with run_sync + # async with mod.engine.connect() as conn: + # insp: Inspector = await conn.run_sync( + # lambda sync_conn: inspect(sync_conn) + # ) + # assert insp.has_table(str(mod.Hero.__tablename__)) + # assert insp.has_table(str(mod.Team.__tablename__)) + + From b60b13729fc1bca77478f5caccc33bfd30cc8cdd Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Tue, 18 Oct 2022 10:02:07 +1300 Subject: [PATCH 07/13] chore: fixes for mypy static type checks only addresses async tests, does not try to fix other tests use: `mypy docs_src\tutorial_async` and `mypy tests\test_async_tutorial` --- .../test_async_delete/test_async_tutorial001.py | 5 +++-- .../test_async_insert/test_async_tutorial001.py | 5 +++-- .../test_async_tutorial001_tutorial002.py | 9 +++++---- .../test_async_select/test_async_tutorial003.py | 5 +++-- .../test_async_select/test_async_tutorial004.py | 5 +++-- .../test_async_select/test_async_tutorial005.py | 5 +++-- .../test_async_update/test_async_tutorial001.py | 5 +++-- .../test_async_tutorial001_tutorial002.py | 10 +++++----- .../test_async_tutorial003_tutorial004.py | 13 +++++++------ 9 files changed, 35 insertions(+), 27 deletions(-) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py index 30ba65239d..e48999b96b 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py @@ -1,5 +1,6 @@ import pytest from unittest.mock import patch +from typing import Any, List from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker @@ -63,14 +64,14 @@ @pytest.mark.asyncio() -async def test_tutorial_async(clear_sqlmodel): +async def test_tutorial_async(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.connect_async.delete_async import ( tutorial001_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py index a059cf9417..cc079fb4dd 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py @@ -1,5 +1,6 @@ import pytest from unittest.mock import patch +from typing import Any, List from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker @@ -43,14 +44,14 @@ @pytest.mark.asyncio() -async def test_async_tutorial001(clear_sqlmodel): +async def test_async_tutorial001(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.connect_async.insert_async import ( tutorial001_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py index 535f187625..431e9f82f8 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py @@ -1,5 +1,6 @@ import pytest from unittest.mock import patch +from typing import List, Any, Dict from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker @@ -67,14 +68,14 @@ @pytest.mark.asyncio() -async def test_tutorial001(clear_sqlmodel): +async def test_tutorial001(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial001_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) @@ -84,14 +85,14 @@ async def test_tutorial001(clear_sqlmodel): @pytest.mark.asyncio() -async def test_tutorial002(clear_sqlmodel): +async def test_tutorial002(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial002_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py index 10e20e7e9e..6647b13359 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py @@ -1,5 +1,6 @@ import pytest from unittest.mock import patch +from typing import Any, List from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker @@ -79,14 +80,14 @@ @pytest.mark.asyncio() -async def test_tutorial(clear_sqlmodel): +async def test_tutorial(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial003_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py index e401a6d9c2..beae9c1b56 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py @@ -1,5 +1,6 @@ import pytest from unittest.mock import patch +from typing import Any, List from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker @@ -53,14 +54,14 @@ @pytest.mark.asyncio() -async def test_tutorial(clear_sqlmodel): +async def test_tutorial(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial004_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py index 9aa69983aa..e08fe31c38 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py @@ -1,5 +1,6 @@ import pytest from unittest.mock import patch +from typing import Any, List from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker @@ -55,14 +56,14 @@ @pytest.mark.asyncio() -async def test_tutorial(clear_sqlmodel): +async def test_tutorial(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial005_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py index c893a349c6..08bb3820e3 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py @@ -1,5 +1,6 @@ import pytest from unittest.mock import patch +from typing import Any, List from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker @@ -53,14 +54,14 @@ @pytest.mark.asyncio() -async def test_tutorial(clear_sqlmodel): +async def test_tutorial(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.connect_async.update_async import ( tutorial001_async as mod, ) mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) diff --git a/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py b/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py index e932ecad2b..696ff6b81d 100644 --- a/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py +++ b/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py @@ -11,7 +11,7 @@ from tests.conftest import get_testing_print_function -def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]): +def check_calls(calls: List[List[Union[str, Dict[str, Any]]]])->None: assert calls[0][0] == { "name": "Deadpond", "secret_name": "Dive Wilson", @@ -33,12 +33,12 @@ def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]): @pytest.mark.asyncio -async def test_tutorial_async_001(clear_sqlmodel): +async def test_tutorial_async_001(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.select_async import tutorial001_async as mod mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) @@ -48,12 +48,12 @@ async def test_tutorial_async_001(clear_sqlmodel): @pytest.mark.asyncio -async def test_tutorial_async_002(clear_sqlmodel): +async def test_tutorial_async_002(clear_sqlmodel:Any)->None: from docs_src.tutorial_async.select_async import tutorial002_async as mod mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) diff --git a/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py b/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py index da9cba0fb9..6d9475472f 100644 --- a/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py +++ b/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py @@ -11,8 +11,8 @@ from tests.conftest import get_testing_print_function -def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]): - assert calls[0][0] == [ +def check_calls(calls: List[List[List[Union[str, Dict[str, Any]]]]])->None: + expected_result: List[Union[str, Dict[str, Any]]] = [ { "name": "Deadpond", "secret_name": "Dive Wilson", @@ -33,15 +33,16 @@ def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]): }, ] + assert calls[0][0] == expected_result @pytest.mark.asyncio -async def test_tutorial_003(clear_sqlmodel): +async def test_tutorial_003(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial003_async as mod mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) @@ -51,12 +52,12 @@ async def test_tutorial_003(clear_sqlmodel): @pytest.mark.asyncio -async def test_tutorial_004(clear_sqlmodel): +async def test_tutorial_004(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial004_async as mod mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - calls = [] + calls: List[Any] = [] new_print = get_testing_print_function(calls) From 22e93d7dda58b358308bc1d194054e66cd87b094 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Tue, 18 Oct 2022 10:31:50 +1300 Subject: [PATCH 08/13] chore: async test requirements, Drop 3.6 support pytest.asyncio dropped support for python 3.6 with version 0.17.0 (22-01-13) as Python 3.6 EOL (23 Dec 2021) --- pyproject.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7f5e7f8037..e0f77ca422 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,10 +30,11 @@ classifiers = [ ] [tool.poetry.dependencies] -python = "^3.6.1" +python = "^3.7" SQLAlchemy = ">=1.4.17,<=1.4.41" pydantic = "^1.8.2" sqlalchemy2-stubs = {version = "*", allow-prereleases = true} +aiosqlite = "^0.17.0" [tool.poetry.dev-dependencies] pytest = "^6.2.4" @@ -51,6 +52,11 @@ isort = "^5.9.3" async_generator = {version = "*", python = "~3.6"} async-exit-stack = {version = "*", python = "~3.6"} +[tool.poetry.group.dev.dependencies] +pytest-asyncio = "^0.19.0" +SQLAlchemy = {extras = ["asyncio"], version = "^1.4.41"} + + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" From 1151d8586d6b5215f4804e8cd7d2648999d3bdb5 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Tue, 18 Oct 2022 12:16:44 +1300 Subject: [PATCH 09/13] doc: add reference in docs to the async tutorial also references tests and major PR dependencies --- docs/advanced/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/advanced/index.md b/docs/advanced/index.md index f6178249ce..17060bee66 100644 --- a/docs/advanced/index.md +++ b/docs/advanced/index.md @@ -5,6 +5,12 @@ The **Advanced User Guide** is gradually growing, you can already read about som At some point it will include: * How to use `async` and `await` with the async session. +* See: `docs_src\tutorial_async` for working examples as equivalents to `docs_src\tutorial` +* Also see `tests\tutorial_async` for fully functioning pytest tests against the examples +* +* These examples and tests are also passing `mypy` static checking if #PR58 addressing Issue#54 is included +* also note the TODO: for PR#435 subclassing the SQLAlchemey requirements fully into SQLModel +* * How to run migrations. * How to combine **SQLModel** models with SQLAlchemy. * ...and more. 🤓 From 94527a65e1a389009bb78112327d6cfa76a0e9ee Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Tue, 18 Oct 2022 14:41:10 +1300 Subject: [PATCH 10/13] fix: mypy "ForwardRef"; implicit reexport disabled current pydantic 1.10.2 see https://github.com/pydantic/pydantic/pull/4358 Fix imports indirectly from pydantic typing #4358 --- sqlmodel/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index d343c698e9..e342f62311 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -21,6 +21,7 @@ TypeVar, Union, cast, + ForwardRef, ) from pydantic import BaseConfig, BaseModel @@ -29,7 +30,7 @@ from pydantic.fields import FieldInfo as PydanticFieldInfo from pydantic.fields import ModelField, Undefined, UndefinedType from pydantic.main import ModelMetaclass, validate_model -from pydantic.typing import ForwardRef, NoArgAnyCallable, resolve_annotations +from pydantic.typing import NoArgAnyCallable, resolve_annotations from pydantic.utils import ROOT_KEY, Representation from sqlalchemy import Boolean, Column, Date, DateTime from sqlalchemy import Enum as sa_Enum From 1846878ba05043eaa8f484fb3666db899aa1dc2d Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Tue, 18 Oct 2022 20:31:07 +1300 Subject: [PATCH 11/13] chore: fix linting issues --- .../create_tables_async/tutorial001_async.py | 4 +--- .../delete_async/tutorial001_async.py | 3 +-- .../insert_async/tutorial001_async.py | 3 +-- .../select_async/tutorial001_async.py | 1 - .../select_async/tutorial002_async.py | 1 - .../select_async/tutorial003_async.py | 1 - .../select_async/tutorial004_async.py | 1 - .../select_async/tutorial005_async.py | 1 - .../update_async/tutorial001_async.py | 3 +-- .../select_async/tutorial001_async.py | 1 - .../select_async/tutorial002_async.py | 1 - .../select_async/tutorial003_async.py | 1 - .../select_async/tutorial004_async.py | 1 - pyproject.toml | 4 +--- sqlmodel/main.py | 2 +- .../test_async_tutorial001.py | 18 ++++-------------- .../test_async_tutorial001.py | 9 +++------ .../test_async_tutorial001.py | 9 +++------ .../test_async_tutorial001_tutorial002.py | 11 ++++------- .../test_async_tutorial003.py | 9 +++------ .../test_async_tutorial004.py | 9 +++------ .../test_async_tutorial005.py | 9 +++------ .../test_async_tutorial001.py | 9 +++------ .../test_async_tutorial001_tutorial002.py | 12 ++++-------- .../test_async_tutorial003_tutorial004.py | 9 +++------ 25 files changed, 39 insertions(+), 93 deletions(-) diff --git a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py index f63facbf49..f115401afb 100644 --- a/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/create_tables_async/tutorial001_async.py @@ -1,13 +1,11 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlmodel import Field, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession +from sqlmodel import Field, SQLModel class Team(SQLModel, table=True): diff --git a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py index 6e123f7002..cb30eed76e 100644 --- a/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/delete_async/tutorial001_async.py @@ -1,12 +1,11 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlmodel import Field, SQLModel, select +from sqlmodel import Field, SQLModel from sqlmodel.ext.asyncio.session import AsyncSession diff --git a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py index 8958c0c21e..8ee48ee283 100644 --- a/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/insert_async/tutorial001_async.py @@ -1,12 +1,11 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlmodel import Field, SQLModel, select +from sqlmodel import Field, SQLModel from sqlmodel.ext.asyncio.session import AsyncSession diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py index fdf028643b..2d4b12a4cc 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial001_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py index 1d4828b5d7..c3cbf5a046 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial002_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py index 7642c595f3..69162abb31 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial003_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py index 666f265076..c3cb426f26 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial004_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py index fcd04ee2f5..92401b6b63 100644 --- a/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py +++ b/docs_src/tutorial_async/connect_async/select_async/tutorial005_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py b/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py index e7b41de791..e8a87c3a67 100644 --- a/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py +++ b/docs_src/tutorial_async/connect_async/update_async/tutorial001_async.py @@ -1,12 +1,11 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select from sqlalchemy.ext.asyncio import create_async_engine -from sqlmodel import Field, SQLModel, select +from sqlmodel import Field, SQLModel from sqlmodel.ext.asyncio.session import AsyncSession diff --git a/docs_src/tutorial_async/select_async/tutorial001_async.py b/docs_src/tutorial_async/select_async/tutorial001_async.py index c0ec6d1606..8c25ecbb15 100644 --- a/docs_src/tutorial_async/select_async/tutorial001_async.py +++ b/docs_src/tutorial_async/select_async/tutorial001_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/docs_src/tutorial_async/select_async/tutorial002_async.py b/docs_src/tutorial_async/select_async/tutorial002_async.py index 4dbf1c8209..e3ef3a3f56 100644 --- a/docs_src/tutorial_async/select_async/tutorial002_async.py +++ b/docs_src/tutorial_async/select_async/tutorial002_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/docs_src/tutorial_async/select_async/tutorial003_async.py b/docs_src/tutorial_async/select_async/tutorial003_async.py index 9971a6c42f..2ffd07d71a 100644 --- a/docs_src/tutorial_async/select_async/tutorial003_async.py +++ b/docs_src/tutorial_async/select_async/tutorial003_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/docs_src/tutorial_async/select_async/tutorial004_async.py b/docs_src/tutorial_async/select_async/tutorial004_async.py index 8407ae94c4..74389677f4 100644 --- a/docs_src/tutorial_async/select_async/tutorial004_async.py +++ b/docs_src/tutorial_async/select_async/tutorial004_async.py @@ -1,7 +1,6 @@ import asyncio from typing import Annotated, Optional - # TODO change when https://github.com/tiangolo/sqlmodel/pull/435 accepted # TODO replace following 3 lines with: # ------ from sqlmodel import AsyncSession, create_async_engine, Field, SQLModel, select diff --git a/pyproject.toml b/pyproject.toml index e0f77ca422..11ee7c479b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ aiosqlite = "^0.17.0" pytest = "^6.2.4" mypy = "0.930" flake8 = "^3.9.2" -black = {version = "^21.5-beta.1", python = "^3.7"} +black = "^22.10.0" mkdocs = "^1.2.1" mkdocs-material = "^8.1.4" mdx-include = "^1.4.1" @@ -51,8 +51,6 @@ autoflake = "^1.4" isort = "^5.9.3" async_generator = {version = "*", python = "~3.6"} async-exit-stack = {version = "*", python = "~3.6"} - -[tool.poetry.group.dev.dependencies] pytest-asyncio = "^0.19.0" SQLAlchemy = {extras = ["asyncio"], version = "^1.4.41"} diff --git a/sqlmodel/main.py b/sqlmodel/main.py index e342f62311..ba485e65e1 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -11,6 +11,7 @@ Callable, ClassVar, Dict, + ForwardRef, List, Mapping, Optional, @@ -21,7 +22,6 @@ TypeVar, Union, cast, - ForwardRef, ) from pydantic import BaseConfig, BaseModel diff --git a/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py index daeba2bbaa..1eebf631df 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py @@ -1,14 +1,10 @@ import pytest from sqlalchemy import inspect -from sqlalchemy.engine.reflection import Inspector from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Session, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession @pytest.mark.asyncio -async def test_async_tutorial001()->None: +async def test_async_tutorial001() -> None: from docs_src.tutorial_async.connect_async.create_tables_async import ( tutorial001_async as mod, ) @@ -16,12 +12,8 @@ async def test_async_tutorial001()->None: mod.sqlite_url = "sqlite+aiosqlite://" mod.engine = create_async_engine(mod.sqlite_url) - await mod.main() - - - # Following code lines are for sync implementation , see following note regarding async # https://docs.sqlalchemy.org/en/14/errors.html#error-xd3s # insp: Inspector = inspect(mod.engine) @@ -30,9 +22,9 @@ async def test_async_tutorial001()->None: # following is recommended workaround async with mod.engine.connect() as conn: - tables = await conn.run_sync( - lambda sync_conn: inspect(sync_conn).get_table_names() - ) + tables = await conn.run_sync( + lambda sync_conn: inspect(sync_conn).get_table_names() + ) assert str(mod.Team.__tablename__) in tables assert str(mod.Hero.__tablename__) in tables @@ -43,5 +35,3 @@ async def test_async_tutorial001()->None: # ) # assert insp.has_table(str(mod.Hero.__tablename__)) # assert insp.has_table(str(mod.Team.__tablename__)) - - diff --git a/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py index e48999b96b..cd392dce8d 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py @@ -1,11 +1,8 @@ -import pytest +from typing import Any, List from unittest.mock import patch -from typing import Any, List +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Session, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession from tests.conftest import get_testing_print_function @@ -64,7 +61,7 @@ @pytest.mark.asyncio() -async def test_tutorial_async(clear_sqlmodel:Any)->None: +async def test_tutorial_async(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.delete_async import ( tutorial001_async as mod, ) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py index cc079fb4dd..8187d41de8 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py @@ -1,11 +1,8 @@ -import pytest +from typing import Any, List from unittest.mock import patch -from typing import Any, List +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Session, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession from tests.conftest import get_testing_print_function @@ -44,7 +41,7 @@ @pytest.mark.asyncio() -async def test_async_tutorial001(clear_sqlmodel:Any)->None: +async def test_async_tutorial001(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.insert_async import ( tutorial001_async as mod, ) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py index 431e9f82f8..ea05930db3 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py @@ -1,11 +1,8 @@ -import pytest +from typing import Any, List from unittest.mock import patch -from typing import List, Any, Dict +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Session, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession from tests.conftest import get_testing_print_function @@ -68,7 +65,7 @@ @pytest.mark.asyncio() -async def test_tutorial001(clear_sqlmodel:Any)->None: +async def test_tutorial001(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial001_async as mod, ) @@ -85,7 +82,7 @@ async def test_tutorial001(clear_sqlmodel:Any)->None: @pytest.mark.asyncio() -async def test_tutorial002(clear_sqlmodel:Any)->None: +async def test_tutorial002(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial002_async as mod, ) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py index 6647b13359..591c0e317a 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py @@ -1,11 +1,8 @@ -import pytest +from typing import Any, List from unittest.mock import patch -from typing import Any, List +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Session, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession from tests.conftest import get_testing_print_function @@ -80,7 +77,7 @@ @pytest.mark.asyncio() -async def test_tutorial(clear_sqlmodel:Any)->None: +async def test_tutorial(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial003_async as mod, ) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py index beae9c1b56..64a18e8622 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py @@ -1,11 +1,8 @@ -import pytest +from typing import Any, List from unittest.mock import patch -from typing import Any, List +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Session, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession from tests.conftest import get_testing_print_function @@ -54,7 +51,7 @@ @pytest.mark.asyncio() -async def test_tutorial(clear_sqlmodel:Any)->None: +async def test_tutorial(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial004_async as mod, ) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py index e08fe31c38..d50dd97733 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py @@ -1,11 +1,8 @@ -import pytest +from typing import Any, List from unittest.mock import patch -from typing import Any, List +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Session, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession from tests.conftest import get_testing_print_function @@ -56,7 +53,7 @@ @pytest.mark.asyncio() -async def test_tutorial(clear_sqlmodel:Any)->None: +async def test_tutorial(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( tutorial005_async as mod, ) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py index 08bb3820e3..2764b63bdd 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py @@ -1,11 +1,8 @@ -import pytest +from typing import Any, List from unittest.mock import patch -from typing import Any, List +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import Session, SQLModel, select -from sqlmodel.ext.asyncio.session import AsyncSession from tests.conftest import get_testing_print_function @@ -54,7 +51,7 @@ @pytest.mark.asyncio() -async def test_tutorial(clear_sqlmodel:Any)->None: +async def test_tutorial(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.update_async import ( tutorial001_async as mod, ) diff --git a/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py b/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py index 696ff6b81d..efaf0e296b 100644 --- a/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py +++ b/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py @@ -1,17 +1,13 @@ -import pytest from typing import Any, Dict, List, Union from unittest.mock import patch +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import MetaData, Session, SQLModel, create_engine, select -from sqlmodel.ext.asyncio.session import AsyncSession -from sqlmodel import create_engine from tests.conftest import get_testing_print_function -def check_calls(calls: List[List[Union[str, Dict[str, Any]]]])->None: +def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]) -> None: assert calls[0][0] == { "name": "Deadpond", "secret_name": "Dive Wilson", @@ -33,7 +29,7 @@ def check_calls(calls: List[List[Union[str, Dict[str, Any]]]])->None: @pytest.mark.asyncio -async def test_tutorial_async_001(clear_sqlmodel:Any)->None: +async def test_tutorial_async_001(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial001_async as mod mod.sqlite_url = "sqlite+aiosqlite://" @@ -48,7 +44,7 @@ async def test_tutorial_async_001(clear_sqlmodel:Any)->None: @pytest.mark.asyncio -async def test_tutorial_async_002(clear_sqlmodel:Any)->None: +async def test_tutorial_async_002(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial002_async as mod mod.sqlite_url = "sqlite+aiosqlite://" diff --git a/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py b/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py index 6d9475472f..eced1dd1b6 100644 --- a/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py +++ b/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py @@ -1,17 +1,13 @@ -import pytest from typing import Any, Dict, List, Union from unittest.mock import patch +import pytest from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.orm import sessionmaker -from sqlmodel import MetaData, Session, SQLModel, create_engine, select -from sqlmodel.ext.asyncio.session import AsyncSession -from sqlmodel import create_engine from tests.conftest import get_testing_print_function -def check_calls(calls: List[List[List[Union[str, Dict[str, Any]]]]])->None: +def check_calls(calls: List[List[List[Union[str, Dict[str, Any]]]]]) -> None: expected_result: List[Union[str, Dict[str, Any]]] = [ { "name": "Deadpond", @@ -35,6 +31,7 @@ def check_calls(calls: List[List[List[Union[str, Dict[str, Any]]]]])->None: assert calls[0][0] == expected_result + @pytest.mark.asyncio async def test_tutorial_003(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial003_async as mod From 5aed51e28317e8106dac9b1ab392e104aa109d96 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Tue, 18 Oct 2022 23:36:22 +1300 Subject: [PATCH 12/13] tests: fix typing.annotations support only ^3.9 async tutorials not supported with mypy static type checking if python version before 3.9 --- .../test_async_tutorial001.py | 6 ++++++ .../test_async_delete/test_async_tutorial001.py | 6 ++++++ .../test_async_insert/test_async_tutorial001.py | 6 ++++++ .../test_async_tutorial001_tutorial002.py | 7 +++++++ .../test_async_select/test_async_tutorial003.py | 6 ++++++ .../test_async_select/test_async_tutorial004.py | 6 ++++++ .../test_async_select/test_async_tutorial005.py | 6 ++++++ .../test_async_update/test_async_tutorial001.py | 6 ++++++ .../test_async_tutorial001_tutorial002.py | 7 +++++++ .../test_async_tutorial003_tutorial004.py | 7 +++++++ 10 files changed, 63 insertions(+) diff --git a/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py index 1eebf631df..c36285a917 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_create_connected_tables/test_async_tutorial001.py @@ -1,8 +1,14 @@ +import sys + import pytest from sqlalchemy import inspect from sqlalchemy.ext.asyncio import create_async_engine +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio async def test_async_tutorial001() -> None: from docs_src.tutorial_async.connect_async.create_tables_async import ( diff --git a/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py index cd392dce8d..796b33024b 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_delete/test_async_tutorial001.py @@ -1,3 +1,4 @@ +import sys from typing import Any, List from unittest.mock import patch @@ -60,6 +61,11 @@ ] +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio() async def test_tutorial_async(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.delete_async import ( diff --git a/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py index 8187d41de8..aefdc7a99f 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_insert/test_async_tutorial001.py @@ -1,3 +1,4 @@ +import sys from typing import Any, List from unittest.mock import patch @@ -40,6 +41,11 @@ ] +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio() async def test_async_tutorial001(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.insert_async import ( diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py index ea05930db3..7d2cb667e7 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial001_tutorial002.py @@ -1,3 +1,4 @@ +import sys from typing import Any, List from unittest.mock import patch @@ -64,6 +65,11 @@ ] +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio() async def test_tutorial001(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( @@ -81,6 +87,7 @@ async def test_tutorial001(clear_sqlmodel: Any) -> None: assert calls == expected_calls +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio() async def test_tutorial002(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py index 591c0e317a..f2d7b8e2e8 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial003.py @@ -1,3 +1,4 @@ +import sys from typing import Any, List from unittest.mock import patch @@ -76,6 +77,11 @@ ] +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio() async def test_tutorial(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py index 64a18e8622..2131137579 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial004.py @@ -1,3 +1,4 @@ +import sys from typing import Any, List from unittest.mock import patch @@ -50,6 +51,11 @@ ] +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio() async def test_tutorial(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( diff --git a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py index d50dd97733..468d0532a3 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_select/test_async_tutorial005.py @@ -1,3 +1,4 @@ +import sys from typing import Any, List from unittest.mock import patch @@ -52,6 +53,11 @@ ] +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio() async def test_tutorial(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.select_async import ( diff --git a/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py b/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py index 2764b63bdd..b62072ab93 100644 --- a/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py +++ b/tests/test_async_tutorial/test_async_connect/test_async_update/test_async_tutorial001.py @@ -1,3 +1,4 @@ +import sys from typing import Any, List from unittest.mock import patch @@ -50,6 +51,11 @@ ] +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio() async def test_tutorial(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.connect_async.update_async import ( diff --git a/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py b/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py index efaf0e296b..4ec7fe464e 100644 --- a/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py +++ b/tests/test_async_tutorial/test_async_select/test_async_tutorial001_tutorial002.py @@ -1,3 +1,4 @@ +import sys from typing import Any, Dict, List, Union from unittest.mock import patch @@ -28,6 +29,11 @@ def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]) -> None: } +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio async def test_tutorial_async_001(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial001_async as mod @@ -43,6 +49,7 @@ async def test_tutorial_async_001(clear_sqlmodel: Any) -> None: check_calls(calls) +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio async def test_tutorial_async_002(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial002_async as mod diff --git a/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py b/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py index eced1dd1b6..88d3c79dfe 100644 --- a/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py +++ b/tests/test_async_tutorial/test_async_select/test_async_tutorial003_tutorial004.py @@ -1,3 +1,4 @@ +import sys from typing import Any, Dict, List, Union from unittest.mock import patch @@ -32,6 +33,11 @@ def check_calls(calls: List[List[List[Union[str, Dict[str, Any]]]]]) -> None: assert calls[0][0] == expected_result +beforePYTHON3_9 = sys.version_info < (3, 9) +reasonPEP593 = "Annotations(PEP593 https://peps.python.org/pep-0593/) only compatible with Python ver >= 3.9" + + +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio async def test_tutorial_003(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial003_async as mod @@ -48,6 +54,7 @@ async def test_tutorial_003(clear_sqlmodel: Any) -> None: check_calls(calls) +@pytest.mark.skipif(beforePYTHON3_9, reason=reasonPEP593) @pytest.mark.asyncio async def test_tutorial_004(clear_sqlmodel: Any) -> None: from docs_src.tutorial_async.select_async import tutorial004_async as mod From 6d00e2c1d367172346379cff872eb3b069de2e43 Mon Sep 17 00:00:00 2001 From: Anthony Uphof Date: Wed, 19 Oct 2022 09:13:12 +1300 Subject: [PATCH 13/13] chore: fix for flake8 on python3.7 flake8 not compatible with 22Oct1 release of importlib_metadata v5 see https://github.com/PyCQA/flake8/issues/1701 set importlib_metadata to 4.13.0 --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 11ee7c479b..ed9bbad9bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,8 @@ aiosqlite = "^0.17.0" [tool.poetry.dev-dependencies] pytest = "^6.2.4" mypy = "0.930" -flake8 = "^3.9.2" +flake8 = "^3.8" +importlib-metadata = "4.13.0" #required for flake8 with 3.7 see https://github.com/PyCQA/flake8/issues/1701 black = "^22.10.0" mkdocs = "^1.2.1" mkdocs-material = "^8.1.4"