Skip to content

Commit 32e13c3

Browse files
authored
Fix manager types scope (#991)
* Fix manager types scope * Restore incremental mode and mention in developer docs * Separate dev mypy config and regular one * Document config files usage
1 parent ae5b1a4 commit 32e13c3

File tree

8 files changed

+73
-8
lines changed

8 files changed

+73
-8
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646
pip install -r ./requirements.txt
4747
4848
- name: Run tests
49-
run: pytest
49+
run: pytest --mypy-ini-file=mypy.ini
5050

5151
typecheck:
5252
runs-on: ubuntu-latest

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ To execute the unit tests, simply run:
7070
pytest
7171
```
7272

73+
If you get some unexpected results or want to be sure that tests run is not affected by previous one, remove `mypy` cache:
74+
75+
```bash
76+
rm -r .mypy_cache
77+
```
78+
7379
We also test the stubs against Django's own test suite. This is done in CI but you can also do this locally.
7480
To execute the script run:
7581

mypy.ini

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# Regular configuration file (can be used as base in other projects, runs in CI)
2+
3+
# NOTE: this config file is not used by pytest locally.
4+
# See comment in mypy.ini.dev for explanation.
5+
6+
# WARNING: when changing this file, consider doing the same with mypy.ini.dev
7+
18
[mypy]
29
allow_redefinition = True
310
check_untyped_defs = True

mypy.ini.dev

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Configuration file to use during development
2+
3+
# Changes of plugin code are not detected by mypy, so
4+
# incremental mode can be harmful during development
5+
# (mypy cache is not always invalidated).
6+
# However, incremental mode has to be supported by django-stubs,
7+
# thus another config (mypy.ini) is used in CI.
8+
# Incremental mode is recommended for regular usage.
9+
10+
# WARNING: when changing this file, consider doing the same with mypy.ini
11+
12+
[mypy]
13+
allow_redefinition = True
14+
check_untyped_defs = True
15+
ignore_missing_imports = True
16+
# Avoid caching between test runs
17+
incremental = False
18+
strict_optional = True
19+
show_traceback = True
20+
warn_no_return = False
21+
warn_unused_ignores = True
22+
warn_redundant_casts = True
23+
warn_unused_configs = True
24+
warn_unreachable = True
25+
26+
plugins =
27+
mypy_django_plugin.main
28+
29+
[mypy.plugins.django-stubs]
30+
django_settings_module = scripts.django_tests_settings

mypy_django_plugin/lib/helpers.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -369,11 +369,10 @@ def bind_or_analyze_type(t: MypyType, api: SemanticAnalyzer, module_name: Option
369369
That should hopefully give a bound type."""
370370
if isinstance(t, UnboundType) and module_name is not None:
371371
node = api.lookup_fully_qualified_or_none(module_name + "." + t.name)
372-
if node is None:
373-
return None
374-
return node.type
375-
else:
376-
return api.anal_type(t)
372+
if node is not None and node.type is not None:
373+
return node.type
374+
375+
return api.anal_type(t)
377376

378377

379378
def copy_method_to_another_class(

mypy_django_plugin/transformers/models.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,11 @@ def create_new_model_parametrized_manager(self, name: str, base_manager_info: Ty
212212
# replace self type with new class, if copying method
213213
if isinstance(sym.node, FuncDef):
214214
helpers.copy_method_to_another_class(
215-
new_cls_def_context, self_type=custom_manager_type, new_method_name=name, method_node=sym.node
215+
new_cls_def_context,
216+
self_type=custom_manager_type,
217+
new_method_name=name,
218+
method_node=sym.node,
219+
original_module_name=base_manager_info.module_name,
216220
)
217221
continue
218222

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ addopts =
77
-s
88
-v
99
--cache-clear
10-
--mypy-ini-file=./mypy.ini
10+
--mypy-ini-file=./mypy.ini.dev
1111
--mypy-extension-hook=scripts.tests_extension_hook.django_plugin_hook

tests/typecheck/managers/test_managers.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,3 +423,22 @@
423423
class MyModel(models.Model):
424424
425425
objects = MyModelManager()
426+
427+
- case: regression_manager_scope_foreign
428+
main: |
429+
from myapp.models import MyModel
430+
reveal_type(MyModel.on_site) # N: Revealed type is "myapp.models.MyModel_CurrentSiteManager[myapp.models.MyModel]"
431+
installed_apps:
432+
- myapp
433+
- django.contrib.sites
434+
files:
435+
- path: myapp/__init__.py
436+
- path: myapp/models.py
437+
content: |
438+
from django.db import models
439+
from django.contrib.sites.models import Site
440+
from django.contrib.sites.managers import CurrentSiteManager
441+
442+
class MyModel(models.Model):
443+
site = models.ForeignKey(Site, on_delete=models.CASCADE)
444+
on_site = CurrentSiteManager()

0 commit comments

Comments
 (0)