Skip to content

Commit bc907af

Browse files
authored
[dev]: Replace mypy with ty (experimental) (#573)
* [dev]: Replace mypy with ty (experimental) * Fix ruff+ty conflicts
1 parent 5fb5334 commit bc907af

File tree

8 files changed

+45
-33
lines changed

8 files changed

+45
-33
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
lint-command:
1919
- ruff check --output-format=github .
2020
- black --check --diff .
21-
- mypy model_bakery
21+
- ty check model_bakery
2222
steps:
2323
- uses: actions/checkout@v6
2424
- name: Install uv

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

1212
### Changed
13+
- [dev] Replace mypy with ty as the primary type checker with stricter type checks
1314

1415
### Removed
1516

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ release:
1212
lint:
1313
@black .
1414
@ruff check .
15-
@mypy model_bakery
15+
@ty check model_bakery
1616

1717
.PHONY: help test release lint

model_bakery/baker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ def _handle_m2m(self, instance: Model):
719719
m2m_relation.source_field_name: instance,
720720
m2m_relation.target_field_name: value,
721721
}
722-
make(
722+
make( # ty: ignore[no-matching-overload]
723723
cast(type[Model], through_model),
724724
_using=self._using,
725725
**base_kwargs,

model_bakery/generators.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@
4343
# PostgreSQL-specific field (only available when psycopg is installed)
4444
from django.contrib.postgres.fields import ArrayField
4545
except ImportError:
46-
ArrayField = None
46+
ArrayField = None # type: ignore[misc,assignment]
4747

4848
try:
4949
# PostgreSQL-specific field (only available when psycopg is installed)
5050
from django.contrib.postgres.fields import HStoreField
5151
except ImportError:
52-
HStoreField = None
52+
HStoreField = None # type: ignore[misc,assignment]
5353

5454
try:
5555
# PostgreSQL-specific fields (only available when psycopg is installed)
@@ -59,9 +59,9 @@
5959
CITextField,
6060
)
6161
except ImportError:
62-
CICharField = None
63-
CIEmailField = None
64-
CITextField = None
62+
CICharField = None # type: ignore[misc,assignment]
63+
CIEmailField = None # type: ignore[misc,assignment]
64+
CITextField = None # type: ignore[misc,assignment]
6565

6666

6767
try:
@@ -74,11 +74,11 @@
7474
IntegerRangeField,
7575
)
7676
except ImportError:
77-
BigIntegerRangeField = None
78-
DateRangeField = None
79-
DateTimeRangeField = None
80-
DecimalRangeField = None
81-
IntegerRangeField = None
77+
BigIntegerRangeField = None # type: ignore[misc,assignment]
78+
DateRangeField = None # type: ignore[misc,assignment]
79+
DateTimeRangeField = None # type: ignore[misc,assignment]
80+
DecimalRangeField = None # type: ignore[misc,assignment]
81+
IntegerRangeField = None # type: ignore[misc,assignment]
8282

8383

8484
default_mapping = {

model_bakery/random_gen.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,11 @@ def gen_pg_numbers_range(number_cast: Callable[[int], Any]) -> Callable:
515515

516516
def gen_range():
517517
try:
518-
from psycopg.types.range import Range
518+
from psycopg.types.range import Range # ty: ignore[unresolved-import]
519519
except ImportError:
520-
from psycopg2._range import NumericRange as Range
520+
from psycopg2._range import ( # ty: ignore[unresolved-import]
521+
NumericRange as Range,
522+
)
521523

522524
base_num = baker_random.randint(1, 100000)
523525
return Range(number_cast(-1 * base_num), number_cast(base_num))
@@ -533,9 +535,9 @@ def gen_date_range():
533535
to avoid empty ranges in tests.
534536
"""
535537
try:
536-
from psycopg.types.range import DateRange
538+
from psycopg.types.range import DateRange # ty: ignore[unresolved-import]
537539
except ImportError:
538-
from psycopg2.extras import DateRange
540+
from psycopg2.extras import DateRange # ty: ignore[unresolved-import]
539541

540542
base_date = gen_date()
541543
interval = gen_interval(min_interval=24 * 60 * 60 * 1000)
@@ -551,9 +553,13 @@ def gen_datetime_range():
551553
to avoid empty ranges in tests.
552554
"""
553555
try:
554-
from psycopg.types.range import TimestamptzRange
556+
from psycopg.types.range import ( # ty: ignore[unresolved-import]
557+
TimestamptzRange,
558+
)
555559
except ImportError:
556-
from psycopg2.extras import DateTimeTZRange as TimestamptzRange
560+
from psycopg2.extras import ( # ty: ignore[unresolved-import]
561+
DateTimeTZRange as TimestamptzRange,
562+
)
557563

558564
base_datetime = gen_datetime()
559565
interval = gen_interval(min_interval=24 * 60 * 60 * 1000)

model_bakery/recipe.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@
55
Any,
66
Generic,
77
TypeVar,
8-
cast,
98
overload,
109
)
1110

12-
from django.db.models import Model
13-
1411
from . import baker
1512
from ._types import M
1613
from .exceptions import RecipeNotFound
@@ -178,19 +175,19 @@ def extend(self: _T, **attrs: Any) -> _T:
178175
return type(self)(self._model, **attr_mapping)
179176

180177

181-
def _load_recipe_from_calling_module(recipe: str) -> Recipe[Model]:
178+
def _load_recipe_from_calling_module(recipe_name: str) -> Recipe[Any]:
182179
"""Load `Recipe` from the string attribute given from the calling module.
183180
184181
Args:
185-
recipe (str): the name of the recipe attribute within the module from
182+
recipe_name (str): the name of the recipe attribute within the module from
186183
which it should be loaded
187184
188185
Returns:
189186
(Recipe): recipe resolved from calling module
190187
"""
191-
recipe = getattr(get_calling_module(2), recipe)
188+
recipe = getattr(get_calling_module(2), recipe_name)
192189
if recipe:
193-
return cast(Recipe[Model], recipe)
190+
return recipe
194191
else:
195192
raise RecipeNotFound
196193

@@ -217,16 +214,19 @@ def foreign_key(
217214
This resolves recipes supplied as strings from other module paths or from
218215
the calling code's module.
219216
"""
217+
resolved_recipe: Recipe[M]
220218
if isinstance(recipe, str):
221219
# Load `Recipe` from string before handing off to `RecipeForeignKey`
222220
try:
223221
# Try to load from another module
224-
recipe = baker._recipe(recipe)
222+
resolved_recipe = baker._recipe(recipe)
225223
except (AttributeError, ImportError, ValueError):
226224
# Probably not in another module, so load it from calling module
227-
recipe = _load_recipe_from_calling_module(cast(str, recipe))
225+
resolved_recipe = _load_recipe_from_calling_module(recipe)
226+
else:
227+
resolved_recipe = recipe
228228

229-
return RecipeForeignKey(cast(Recipe[M], recipe), one_to_one)
229+
return RecipeForeignKey(resolved_recipe, one_to_one)
230230

231231

232232
class related(Generic[M]): # FIXME

pyproject.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ dev = [
5959
"pytest-django",
6060
"black",
6161
"ruff",
62-
"mypy",
62+
"ty",
6363
]
6464

6565
[project.urls]
@@ -84,9 +84,14 @@ source = [
8484
[tool.coverage.report]
8585
show_missing = true
8686

87-
[tool.mypy]
88-
ignore_missing_imports = true
89-
disallow_untyped_calls = true
87+
[tool.ty.rules]
88+
# Django dynamic attributes (.objects, ._meta, etc.)
89+
# TODO: remove these two ignores when ty adds better Django support
90+
# https://github.com/astral-sh/ty/issues/1018
91+
unresolved-attribute = "ignore"
92+
possibly-missing-attribute = "ignore"
93+
# Allow `# type: ignore` comments (mypy syntax) without warnings
94+
unused-ignore-comment = "ignore"
9095

9196
[tool.pytest.ini_options]
9297
addopts = "--tb=short -rxs --nomigrations"

0 commit comments

Comments
 (0)