Skip to content

Commit 18736f5

Browse files
authored
Merge pull request #27 from gianchub/improve-desc
Remove Python 3.9
2 parents 12913f2 + 565385d commit 18736f5

File tree

14 files changed

+121
-783
lines changed

14 files changed

+121
-783
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
python-version: ["3.9", "3.14"]
14+
python-version: ["3.10", "3.14"]
1515

1616
steps:
1717
- uses: actions/checkout@v4
@@ -37,7 +37,7 @@ jobs:
3737
runs-on: ubuntu-latest
3838
strategy:
3939
matrix:
40-
python-version: ["3.9", "3.14"]
40+
python-version: ["3.10", "3.14"]
4141

4242
steps:
4343
- uses: actions/checkout@v4
@@ -63,7 +63,7 @@ jobs:
6363
runs-on: ubuntu-latest
6464
strategy:
6565
matrix:
66-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
66+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
6767
tests-command: ["test", "test-sqlalchemy14"]
6868

6969
services:

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
# Changelog
22

3+
## [1.0.3]
4+
5+
15/11/2025
6+
7+
- Improve project description.
8+
- Remove support for Python 3.9.
9+
- Update type hint syntax to be compatible with Python 3.10.
10+
- Update pytest to 9.*.
11+
312
## [1.0.2]
413

14+
15/11/2025
15+
516
- Fix issus with sqlalchemy-utils being pinned too strictly.
617
- Fix tox issues.
718
- Remove print statements from tests.
819
- Fix issues with type hints.
920

1021
## [1.0.0]
1122

23+
- Version 1.0.0.
24+
- This version breaks compatibility with any previous versions of the library.

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ ty:
4242
# requirements
4343

4444
install-reqs:
45-
uv pip install -e ."[dev,lint,test]"
45+
uv pip install -U -e ."[dev,lint,test]"
4646

4747
install-tox-uv:
4848
uv tool install tox --with tox-uv

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# SQLAlchemy Diff
22

3-
A tool for comparing SQLAlchemy models.
3+
A tool for comparing database schemas using SQLAlchemy.
44

55
## Requirements
66

7-
- Python 3.9 or higher (supports 3.9, 3.10, 3.11, 3.12, 3.13, 3.14)
7+
- Python 3.10 or higher (supports 3.10, 3.11, 3.12, 3.13, 3.14)
88
- SQLAlchemy >= 1.4
99
- sqlalchemy-utils ~= 0.41.2
1010

@@ -100,7 +100,7 @@ class MyCustomInspector(BaseInspector, DiffMixin):
100100
# Set to False if it operates at table level (like columns, indexes)
101101
db_level = False
102102

103-
def inspect(self, engine: Engine, ignore_specs: Optional[list] = None) -> dict:
103+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
104104
"""
105105
Inspect the database and return structured data.
106106
@@ -161,7 +161,7 @@ class SequencesInspector(BaseInspector, DiffMixin):
161161
key = "sequences"
162162
db_level = True
163163

164-
def inspect(self, engine: Engine, ignore_specs: Optional[list] = None) -> dict:
164+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
165165
ignore_clauses = self._filter_ignorers(ignore_specs)
166166
inspector = self._get_inspector(engine)
167167

pyproject.toml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
[project]
22
name = "sqlalchemy-diff"
3-
version = "1.0.2"
3+
version = "1.0.3"
44
authors = [
55
{ name = "Fabrizio Romano", email = "[email protected]" },
66
{ name = "Mark McArdle", email = "[email protected]" },
77
]
8-
description = "A tool for comparing SQLAlchemy models"
8+
description = "A tool for comparing database schemas using SQLAlchemy"
99
readme = "README.md"
1010
license-files = ["LICEN[CS]E*"]
11-
requires-python = ">=3.9"
11+
requires-python = ">=3.10"
1212
classifiers = [
1313
"Programming Language :: Python :: 3",
14-
"Programming Language :: Python :: 3.9",
1514
"Programming Language :: Python :: 3.10",
1615
"Programming Language :: Python :: 3.11",
1716
"Programming Language :: Python :: 3.12",
@@ -46,7 +45,7 @@ lint = [
4645
"ty",
4746
]
4847
test = [
49-
"pytest~=8.4.2",
48+
"pytest~=9.0.1",
5049
"pytest-cov~=7.0.0",
5150
"psycopg2-binary",
5251
"pytest-xdist>=3.8.0",
@@ -82,7 +81,7 @@ line-length = 100
8281

8382
[tool.ruff]
8483
line-length = 100
85-
target-version = "py39"
84+
target-version = "py310"
8685

8786
[tool.ruff.format]
8887
# Like Black, use double quotes for strings.

src/sqlalchemydiff/comparer.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
from collections.abc import Iterable
44
from copy import deepcopy
5-
from typing import Any, Optional
5+
from typing import Any
66

77
from sqlalchemy.engine import Engine
88

@@ -104,8 +104,8 @@ def from_params(
104104
cls,
105105
db_one_uri: str,
106106
db_two_uri: str,
107-
db_one_params: Optional[dict[str, Any]] = None,
108-
db_two_params: Optional[dict[str, Any]] = None,
107+
db_one_params: dict[str, Any] | None = None,
108+
db_two_params: dict[str, Any] | None = None,
109109
):
110110
db_one_params = db_one_params or {}
111111
db_two_params = db_two_params or {}
@@ -118,8 +118,8 @@ def compare(
118118
self,
119119
one_alias: str = "one",
120120
two_alias: str = "two",
121-
ignores: Optional[list[str]] = None,
122-
ignore_inspectors: Optional[Iterable[str]] = None,
121+
ignores: list[str] | None = None,
122+
ignore_inspectors: Iterable[str] | None = None,
123123
):
124124
ignore_specs = self.ignore_spec_factory_class().create_specs(register, ignores)
125125

@@ -139,7 +139,7 @@ def compare(
139139
return self.compare_result_class(result, one_alias=one_alias, two_alias=two_alias)
140140

141141
def _filter_inspectors(
142-
self, ignore_inspectors: Optional[set[str]]
142+
self, ignore_inspectors: set[str] | None
143143
) -> list[tuple[str, type[BaseInspector]]]:
144144
if not ignore_inspectors:
145145
ignore_inspectors = set()
@@ -152,7 +152,7 @@ def _filter_inspectors(
152152

153153
def _get_db_info(
154154
self, ignore_specs: list[IgnoreSpecType], inspector: BaseInspector, engine: Engine
155-
) -> Optional[dict]:
155+
) -> dict | None:
156156
try:
157157
return inspector.inspect(engine, ignore_specs)
158158
except InspectorNotSupported as e:

src/sqlalchemydiff/inspection/base.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import abc
22
import inspect as stdlib_inspect
3-
from typing import Optional
43

54
from sqlalchemy import inspect
65
from sqlalchemy.engine import Engine
@@ -59,7 +58,7 @@ def __init__(self, one_alias: str = "one", two_alias: str = "two"):
5958

6059
@abc.abstractmethod
6160
def inspect(
62-
self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None
61+
self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None
6362
) -> dict: ... # pragma: no cover
6463

6564
@abc.abstractmethod
@@ -68,7 +67,7 @@ def diff(self, one: dict, two: dict) -> dict: ... # pragma: no cover
6867
@abc.abstractmethod
6968
def _is_supported(self, inspector: Inspector) -> bool: ... # pragma: no cover
7069

71-
def _filter_ignorers(self, specs: Optional[list[IgnoreSpecType]]) -> IgnoreClauses:
70+
def _filter_ignorers(self, specs: list[IgnoreSpecType] | None) -> IgnoreClauses:
7271
tables, enums, clauses = [], [], []
7372

7473
for spec in specs or []:

src/sqlalchemydiff/inspection/ignore.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
from dataclasses import dataclass, field
2-
from typing import NamedTuple, Optional, Union
2+
from typing import NamedTuple
33

44

55
class TableIgnoreSpec(NamedTuple):
66
table_name: str
7-
inspector_key: Optional[str] = None
8-
object_name: Optional[str] = None
7+
inspector_key: str | None = None
8+
object_name: str | None = None
99

1010

1111
class EnumIgnoreSpec(NamedTuple):
1212
name: str
1313

1414

15-
IgnoreSpecType = Union[TableIgnoreSpec, EnumIgnoreSpec]
15+
IgnoreSpecType = TableIgnoreSpec | EnumIgnoreSpec
1616

1717

1818
class IgnoreSpecFactory:
@@ -29,9 +29,7 @@ class IgnoreSpecFactory:
2929
separator = "."
3030

3131
@classmethod
32-
def create_specs(
33-
cls, register: dict, ignores: Optional[list[str]] = None
34-
) -> list[IgnoreSpecType]:
32+
def create_specs(cls, register: dict, ignores: list[str] | None = None) -> list[IgnoreSpecType]:
3533
if not ignores:
3634
return []
3735

@@ -64,6 +62,6 @@ class IgnoreClauses:
6462
enums: list[str] = field(default_factory=list)
6563
clauses: list[IgnoreSpecType] = field(default_factory=list)
6664

67-
def is_clause(self, table_name: str, inspector_key: str, object_name: Optional[str]) -> bool:
65+
def is_clause(self, table_name: str, inspector_key: str, object_name: str | None) -> bool:
6866
clause = TableIgnoreSpec(table_name, inspector_key, object_name)
6967
return clause in self.clauses

src/sqlalchemydiff/inspection/inspectors.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional, cast
1+
from typing import cast
22

33
from sqlalchemy.engine import Engine
44

@@ -14,11 +14,11 @@ class TablesInspector(BaseInspector, DiffMixin):
1414
key = "tables"
1515
db_level = True
1616

17-
def inspect(self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None) -> dict:
17+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
1818
ignore_clauses = self._filter_ignorers(ignore_specs)
1919
inspector = self._get_inspector(engine)
2020

21-
def get_comment(table_name: str) -> Optional[str]:
21+
def get_comment(table_name: str) -> str | None:
2222
try:
2323
return inspector.get_table_comment(table_name)["text"]
2424
except NotImplementedError:
@@ -30,7 +30,7 @@ def get_comment(table_name: str) -> Optional[str]:
3030
if table_name not in ignore_clauses.tables
3131
}
3232

33-
def _format_table(self, table_name: str, comment: Optional[str] = None) -> dict:
33+
def _format_table(self, table_name: str, comment: str | None = None) -> dict:
3434
return {
3535
"name": table_name,
3636
"comment": comment or "",
@@ -48,7 +48,7 @@ class ColumnsInspector(BaseInspector, DiffMixin):
4848

4949
key = "columns"
5050

51-
def inspect(self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None) -> dict:
51+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
5252
ignore_clauses = self._filter_ignorers(ignore_specs)
5353

5454
inspector = self._get_inspector(engine)
@@ -90,7 +90,7 @@ class PrimaryKeysInspector(BaseInspector, DiffMixin):
9090

9191
key = "primary_keys"
9292

93-
def inspect(self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None) -> dict:
93+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
9494
ignore_clauses = self._filter_ignorers(ignore_specs)
9595

9696
inspector = self._get_inspector(engine)
@@ -121,7 +121,7 @@ class ForeignKeysInspector(BaseInspector, DiffMixin):
121121

122122
key = "foreign_keys"
123123

124-
def inspect(self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None) -> dict:
124+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
125125
ignore_clauses = self._filter_ignorers(ignore_specs)
126126

127127
inspector = self._get_inspector(engine)
@@ -155,7 +155,7 @@ class IndexesInspector(BaseInspector, DiffMixin):
155155

156156
key = "indexes"
157157

158-
def inspect(self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None) -> dict:
158+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
159159
ignore_clauses = self._filter_ignorers(ignore_specs)
160160
inspector = self._get_inspector(engine)
161161
table_names = inspector.get_table_names()
@@ -183,7 +183,7 @@ class UniqueConstraintsInspector(BaseInspector, DiffMixin):
183183

184184
key = "unique_constraints"
185185

186-
def inspect(self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None) -> dict:
186+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
187187
ignore_clauses = self._filter_ignorers(ignore_specs)
188188
inspector = self._get_inspector(engine)
189189
table_names = inspector.get_table_names()
@@ -220,7 +220,7 @@ class CheckConstraintsInspector(BaseInspector, DiffMixin):
220220

221221
key = "check_constraints"
222222

223-
def inspect(self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None) -> dict:
223+
def inspect(self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None) -> dict:
224224
ignore_clauses = self._filter_ignorers(ignore_specs)
225225
inspector = self._get_inspector(engine)
226226
table_names = inspector.get_table_names()
@@ -250,7 +250,7 @@ class EnumsInspector(BaseInspector, DiffMixin):
250250
db_level = True
251251

252252
def inspect(
253-
self, engine: Engine, ignore_specs: Optional[list[IgnoreSpecType]] = None
253+
self, engine: Engine, ignore_specs: list[IgnoreSpecType] | None = None
254254
) -> list[dict]:
255255
inspector = self._get_inspector(engine)
256256

tests/models/models_one.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# ty: ignore[invalid-assignment]
22
import datetime
33
import enum
4-
from typing import Optional
54

65
from sqlalchemy import (
76
CheckConstraint,
@@ -36,8 +35,8 @@ class Employee(Base):
3635
age: Mapped[int] = Column(Integer, nullable=False, default=21)
3736
ssn: Mapped[str] = Column(Unicode(30), nullable=False)
3837
number_of_pets: Mapped[int] = Column(Integer, default=1, nullable=False)
39-
title: Mapped[Optional[Title]] = Column(Enum(Title, native_enum=True))
40-
department: Mapped[Optional[str]] = Column( # ty: ignore[invalid-assignment]
38+
title: Mapped[Title | None] = Column(Enum(Title, native_enum=True))
39+
department: Mapped[str | None] = Column( # ty: ignore[invalid-assignment]
4140
Enum("Product", "Engineering", "Sales", native_enum=False)
4241
)
4342

@@ -77,7 +76,7 @@ class Role(Base):
7776

7877
employees: Mapped[list["Employee"]] = relationship("Employee", back_populates="role")
7978

80-
role_type: Mapped[Optional[str]] = Column(Enum("Permanent", "Contractor", name="role_type"))
79+
role_type: Mapped[str | None] = Column(Enum("Permanent", "Contractor", name="role_type"))
8180

8281

8382
class Skill(Base):
@@ -87,7 +86,7 @@ class Skill(Base):
8786
}
8887

8988
slug: Mapped[str] = Column(String(50), primary_key=True)
90-
description: Mapped[Optional[str]] = Column(Unicode(100), nullable=True)
89+
description: Mapped[str | None] = Column(Unicode(100), nullable=True)
9190

9291
employee: Mapped[int] = Column(
9392
Integer, ForeignKey("employees.id", name="fk_skills_employees"), nullable=False

0 commit comments

Comments
 (0)