Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migration to sqlalchemy 2.0 #563

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
60318b4
migration to sqlalchemy 2.0
farahats9 Mar 7, 2023
48ddc61
fix some linting errors
farahats9 Mar 24, 2023
b48423f
remove unused imports
farahats9 Mar 24, 2023
9c219d9
Update sqlmodel/sql/expression.py
farahats9 Mar 31, 2023
37ed979
reflecting python 3.6 deprecation in docs and tests
farahats9 Mar 31, 2023
0eee8e8
Merge branch 'main' of https://github.com/farahats9/sqlmodel
farahats9 Mar 31, 2023
050cf02
resolving @sbor23 comments
farahats9 Mar 31, 2023
fbff99c
add the new Subquery class
farahats9 Apr 30, 2023
6d8f527
update to latest sqlalchemy version
farahats9 Apr 30, 2023
4ce8d07
fix jinja2 template
farahats9 Apr 30, 2023
ecfb321
`Result` expects a type `Tuple[_T]`
peterlandry Jul 26, 2023
3738a7f
Remove unused type ignore
peterlandry Jul 26, 2023
814988b
Result seems well enough typed in SqlAlchemy now we can simply shim over
peterlandry Jul 26, 2023
118ca33
Implicit export of ForwardRef was remove in pydantic
peterlandry Jul 26, 2023
9170729
_Select expects a `Tuple[Any, ...]`
peterlandry Jul 26, 2023
7f5ba1c
Use Dict type instead of Mapping for SqlAlchemy compat
peterlandry Jul 26, 2023
e942e5e
Execution options are not Optional in SA
peterlandry Jul 26, 2023
ef9f00a
Another instance of non-optional execution_options
peterlandry Jul 26, 2023
643cea5
Fix Tuple in jinja template as well
peterlandry Jul 26, 2023
b89adbb
Use ForUpdateArg from sqlalchemy
peterlandry Jul 26, 2023
eff0803
Fix signature for `Session.get`
peterlandry Jul 26, 2023
c5bdbcc
Merge pull request #2 from peterlandry/main
farahats9 Jul 27, 2023
1752f0b
formatting and remove unused type
farahats9 Jul 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: ["3.6.15", "3.7", "3.8", "3.9", "3.10"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
fail-fast: false

steps:
Expand Down Expand Up @@ -54,7 +54,7 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true'
run: python -m poetry install
- name: Lint
if: ${{ matrix.python-version != '3.6.15' }}
if: ${{ matrix.python-version != '3.7' }}
farahats9 marked this conversation as resolved.
Show resolved Hide resolved
run: python -m poetry run bash scripts/lint.sh
- run: mkdir coverage
- name: Test
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ It combines SQLAlchemy and Pydantic and tries to simplify the code you write as

## Requirements

A recent and currently supported version of Python (right now, <a href="https://www.python.org/downloads/" class="external-link" target="_blank">Python supports versions 3.6 and above</a>).
A recent and currently supported version of Python (right now, <a href="https://www.python.org/downloads/" class="external-link" target="_blank">Python supports versions 3.7 and above</a>).

As **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. They will be automatically installed when you install SQLModel.

Expand Down
2 changes: 1 addition & 1 deletion docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ If you already cloned the repository and you know that you need to deep dive in

### Python

SQLModel supports Python 3.6 and above, but for development you should have at least **Python 3.7**.
SQLModel supports Python 3.7 and above, but for development you should have at least **Python 3.7**.
farahats9 marked this conversation as resolved.
Show resolved Hide resolved

### Poetry

Expand Down
2 changes: 1 addition & 1 deletion docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Nevertheless, SQLModel is completely **independent** of FastAPI and can be used

## Just Modern Python

It's all based on standard <abbr title="Python currently supported versions, 3.6 and above.">modern **Python**</abbr> type annotations. No new syntax to learn. Just standard modern Python.
It's all based on standard <abbr title="Python currently supported versions, 3.7 and above.">modern **Python**</abbr> type annotations. No new syntax to learn. Just standard modern Python.

If you need a 2 minute refresher of how to use Python types (even if you don't use SQLModel or FastAPI), check the FastAPI tutorial section: <a href="https://fastapi.tiangolo.com/python-types/" class="external-link" target="_blank">Python types intro</a>.

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ It combines SQLAlchemy and Pydantic and tries to simplify the code you write as

## Requirements

A recent and currently supported version of Python (right now, <a href="https://www.python.org/downloads/" class="external-link" target="_blank">Python supports versions 3.6 and above</a>).
A recent and currently supported version of Python (right now, <a href="https://www.python.org/downloads/" class="external-link" target="_blank">Python supports versions 3.7 and above</a>).

As **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. They will be automatically installed when you install SQLModel.

Expand Down
3 changes: 1 addition & 2 deletions docs/tutorial/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ $ cd sqlmodel-tutorial

Make sure you have an officially supported version of Python.

Currently it is **Python 3.6** and above (Python 3.5 was already deprecated).
Currently it is **Python 3.7** and above (Python 3.6 was already deprecated).

You can check which version you have with:

Expand All @@ -85,7 +85,6 @@ You might want to try with the specific versions, for example with:
* `python3.9`
* `python3.8`
* `python3.7`
* `python3.6`
farahats9 marked this conversation as resolved.
Show resolved Hide resolved

The code would look like this:

Expand Down
30 changes: 15 additions & 15 deletions docs_src/tutorial/many_to_many/tutorial003.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,12 @@
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select


class HeroTeamLink(SQLModel, table=True):
team_id: Optional[int] = Field(
default=None, foreign_key="team.id", primary_key=True
)
hero_id: Optional[int] = Field(
default=None, foreign_key="hero.id", primary_key=True
)
is_training: bool = False

team: "Team" = Relationship(back_populates="hero_links")
hero: "Hero" = Relationship(back_populates="team_links")


class Team(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
headquarters: str

hero_links: List[HeroTeamLink] = Relationship(back_populates="team")
hero_links: List["HeroTeamLink"] = Relationship(back_populates="team")


class Hero(SQLModel, table=True):
Expand All @@ -30,7 +17,20 @@ class Hero(SQLModel, table=True):
secret_name: str
age: Optional[int] = Field(default=None, index=True)

team_links: List[HeroTeamLink] = Relationship(back_populates="hero")
team_links: List["HeroTeamLink"] = Relationship(back_populates="hero")


class HeroTeamLink(SQLModel, table=True):
team_id: Optional[int] = Field(
default=None, foreign_key="team.id", primary_key=True
)
hero_id: Optional[int] = Field(
default=None, foreign_key="hero.id", primary_key=True
)
is_training: bool = False

team: "Team" = Relationship(back_populates="hero_links")
hero: "Hero" = Relationship(back_populates="team_links")


sqlite_file_name = "database.db"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@
from sqlmodel import Field, Relationship, SQLModel, create_engine


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")
team: Optional["Team"] = Relationship(back_populates="heroes")

weapon_id: Optional[int] = Field(default=None, foreign_key="weapon.id")
weapon: Optional["Weapon"] = Relationship(back_populates="hero")

powers: List["Power"] = Relationship(back_populates="hero")
farahats9 marked this conversation as resolved.
Show resolved Hide resolved


class Weapon(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
Expand All @@ -26,21 +41,6 @@ class Team(SQLModel, table=True):
heroes: List["Hero"] = Relationship(back_populates="team")


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")
team: Optional[Team] = Relationship(back_populates="heroes")

weapon_id: Optional[int] = Field(default=None, foreign_key="weapon.id")
weapon: Optional[Weapon] = Relationship(back_populates="hero")

powers: List[Power] = Relationship(back_populates="hero")


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

Expand Down
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ classifiers = [
"Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Database",
"Topic :: Database :: Database Engines/Servers",
"Topic :: Internet",
Expand All @@ -30,10 +31,9 @@ classifiers = [
]

[tool.poetry.dependencies]
python = "^3.6.1"
SQLAlchemy = ">=1.4.17,<=1.4.41"
python = "^3.7"
SQLAlchemy = ">=2.0.0,<=2.0.5.post1"
farahats9 marked this conversation as resolved.
Show resolved Hide resolved
pydantic = "^1.8.2"
sqlalchemy2-stubs = {version = "*", allow-prereleases = true}

[tool.poetry.dev-dependencies]
pytest = "^7.0.1"
Expand All @@ -50,8 +50,8 @@ fastapi = "^0.68.1"
requests = "^2.26.0"
autoflake = "^1.4"
isort = "^5.9.3"
async_generator = {version = "*", python = "~3.6"}
async-exit-stack = {version = "*", python = "~3.6"}
async_generator = {version = "*", python = "~3.7"}
async-exit-stack = {version = "*", python = "~3.7"}

[build-system]
requires = ["poetry-core"]
Expand Down
2 changes: 0 additions & 2 deletions scripts/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@ mypy sqlmodel
flake8 sqlmodel tests docs_src
black sqlmodel tests docs_src --check
isort sqlmodel tests docs_src scripts --check-only
# TODO: move this to test.sh after deprecating Python 3.6
CHECK_JINJA=1 python scripts/generate_select.py
1 change: 1 addition & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
set -e
set -x

CHECK_JINJA=1 python scripts/generate_select.py
coverage run -m pytest tests
coverage combine
coverage report --show-missing
Expand Down
2 changes: 0 additions & 2 deletions sqlmodel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from sqlalchemy.schema import PrimaryKeyConstraint as PrimaryKeyConstraint
from sqlalchemy.schema import Sequence as Sequence
from sqlalchemy.schema import Table as Table
from sqlalchemy.schema import ThreadLocalMetaData as ThreadLocalMetaData
from sqlalchemy.schema import UniqueConstraint as UniqueConstraint
from sqlalchemy.sql import alias as alias
from sqlalchemy.sql import all_ as all_
Expand Down Expand Up @@ -71,7 +70,6 @@
from sqlalchemy.sql import outerjoin as outerjoin
from sqlalchemy.sql import outparam as outparam
from sqlalchemy.sql import over as over
from sqlalchemy.sql import subquery as subquery
farahats9 marked this conversation as resolved.
Show resolved Hide resolved
from sqlalchemy.sql import table as table
from sqlalchemy.sql import tablesample as tablesample
from sqlalchemy.sql import text as text
Expand Down
2 changes: 1 addition & 1 deletion sqlmodel/engine/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,4 @@ def create_engine(
if not isinstance(query_cache_size, _DefaultPlaceholder):
current_kwargs["query_cache_size"] = query_cache_size
current_kwargs.update(kwargs)
return _create_engine(url, **current_kwargs) # type: ignore
return _create_engine(url, **current_kwargs)
20 changes: 10 additions & 10 deletions sqlmodel/engine/result.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
from typing import Generic, Iterator, List, Optional, TypeVar
from typing import Generic, Iterator, List, Optional, Sequence, TypeVar

from sqlalchemy.engine.result import Result as _Result
from sqlalchemy.engine.result import ScalarResult as _ScalarResult

_T = TypeVar("_T")


class ScalarResult(_ScalarResult, Generic[_T]):
def all(self) -> List[_T]:
class ScalarResult(_ScalarResult[_T], Generic[_T]):
def all(self) -> Sequence[_T]:
return super().all()

def partitions(self, size: Optional[int] = None) -> Iterator[List[_T]]:
def partitions(self, size: Optional[int] = None) -> Iterator[Sequence[_T]]:
return super().partitions(size)

def fetchall(self) -> List[_T]:
def fetchall(self) -> Sequence[_T]:
return super().fetchall()

def fetchmany(self, size: Optional[int] = None) -> List[_T]:
def fetchmany(self, size: Optional[int] = None) -> Sequence[_T]:
farahats9 marked this conversation as resolved.
Show resolved Hide resolved
return super().fetchmany(size)

def __iter__(self) -> Iterator[_T]:
return super().__iter__()

def __next__(self) -> _T:
return super().__next__() # type: ignore
return super().__next__()

def first(self) -> Optional[_T]:
return super().first()
Expand All @@ -32,10 +32,10 @@ def one_or_none(self) -> Optional[_T]:
return super().one_or_none()

def one(self) -> _T:
return super().one() # type: ignore
return super().one()


class Result(_Result, Generic[_T]):
class Result(_Result[_T], Generic[_T]):
def scalars(self, index: int = 0) -> ScalarResult[_T]:
return super().scalars(index) # type: ignore

Expand Down Expand Up @@ -76,4 +76,4 @@ def one(self) -> _T: # type: ignore
return super().one() # type: ignore

def scalar(self) -> Optional[_T]:
return super().scalar()
return super().scalar() # type: ignore
3 changes: 2 additions & 1 deletion sqlmodel/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ class SQLModel(BaseModel, metaclass=SQLModelMetaclass, registry=default_registry
__sqlmodel_relationships__: ClassVar[Dict[str, RelationshipProperty]] # type: ignore
__name__: ClassVar[str]
metadata: ClassVar[MetaData]
__allow_unmapped__ = True # https://docs.sqlalchemy.org/en/20/changelog/migration_20.html#migration-20-step-six
farahats9 marked this conversation as resolved.
Show resolved Hide resolved

class Config:
orm_mode = True
Expand Down Expand Up @@ -521,7 +522,7 @@ def __setattr__(self, name: str, value: Any) -> None:
return
else:
# Set in SQLAlchemy, before Pydantic to trigger events and updates
if getattr(self.__config__, "table", False) and is_instrumented(self, name):
if getattr(self.__config__, "table", False) and is_instrumented(self, name): # type: ignore
set_attribute(self, name, value)
# Set in Pydantic model to trigger possible validation changes, only for
# non relationship values
Expand Down
2 changes: 1 addition & 1 deletion sqlmodel/orm/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def query(self, *entities: Any, **kwargs: Any) -> "_Query[Any]":
Or otherwise you might want to use `session.execute()` instead of
`session.query()`.
"""
return super().query(*entities, **kwargs)
return super().query(*entities, **kwargs) # type: ignore

def get(
self,
Expand Down
Loading