mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-12 23:16:31 +08:00
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
This commit is contained in:
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
|||||||
pip install -r ./requirements.txt
|
pip install -r ./requirements.txt
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: pytest
|
run: pytest --mypy-ini-file=mypy.ini
|
||||||
|
|
||||||
typecheck:
|
typecheck:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -70,6 +70,12 @@ To execute the unit tests, simply run:
|
|||||||
pytest
|
pytest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you get some unexpected results or want to be sure that tests run is not affected by previous one, remove `mypy` cache:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -r .mypy_cache
|
||||||
|
```
|
||||||
|
|
||||||
We also test the stubs against Django's own test suite. This is done in CI but you can also do this locally.
|
We also test the stubs against Django's own test suite. This is done in CI but you can also do this locally.
|
||||||
To execute the script run:
|
To execute the script run:
|
||||||
|
|
||||||
|
|||||||
7
mypy.ini
7
mypy.ini
@@ -1,3 +1,10 @@
|
|||||||
|
# Regular configuration file (can be used as base in other projects, runs in CI)
|
||||||
|
|
||||||
|
# NOTE: this config file is not used by pytest locally.
|
||||||
|
# See comment in mypy.ini.dev for explanation.
|
||||||
|
|
||||||
|
# WARNING: when changing this file, consider doing the same with mypy.ini.dev
|
||||||
|
|
||||||
[mypy]
|
[mypy]
|
||||||
allow_redefinition = True
|
allow_redefinition = True
|
||||||
check_untyped_defs = True
|
check_untyped_defs = True
|
||||||
|
|||||||
30
mypy.ini.dev
Normal file
30
mypy.ini.dev
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Configuration file to use during development
|
||||||
|
|
||||||
|
# Changes of plugin code are not detected by mypy, so
|
||||||
|
# incremental mode can be harmful during development
|
||||||
|
# (mypy cache is not always invalidated).
|
||||||
|
# However, incremental mode has to be supported by django-stubs,
|
||||||
|
# thus another config (mypy.ini) is used in CI.
|
||||||
|
# Incremental mode is recommended for regular usage.
|
||||||
|
|
||||||
|
# WARNING: when changing this file, consider doing the same with mypy.ini
|
||||||
|
|
||||||
|
[mypy]
|
||||||
|
allow_redefinition = True
|
||||||
|
check_untyped_defs = True
|
||||||
|
ignore_missing_imports = True
|
||||||
|
# Avoid caching between test runs
|
||||||
|
incremental = False
|
||||||
|
strict_optional = True
|
||||||
|
show_traceback = True
|
||||||
|
warn_no_return = False
|
||||||
|
warn_unused_ignores = True
|
||||||
|
warn_redundant_casts = True
|
||||||
|
warn_unused_configs = True
|
||||||
|
warn_unreachable = True
|
||||||
|
|
||||||
|
plugins =
|
||||||
|
mypy_django_plugin.main
|
||||||
|
|
||||||
|
[mypy.plugins.django-stubs]
|
||||||
|
django_settings_module = scripts.django_tests_settings
|
||||||
@@ -369,11 +369,10 @@ def bind_or_analyze_type(t: MypyType, api: SemanticAnalyzer, module_name: Option
|
|||||||
That should hopefully give a bound type."""
|
That should hopefully give a bound type."""
|
||||||
if isinstance(t, UnboundType) and module_name is not None:
|
if isinstance(t, UnboundType) and module_name is not None:
|
||||||
node = api.lookup_fully_qualified_or_none(module_name + "." + t.name)
|
node = api.lookup_fully_qualified_or_none(module_name + "." + t.name)
|
||||||
if node is None:
|
if node is not None and node.type is not None:
|
||||||
return None
|
return node.type
|
||||||
return node.type
|
|
||||||
else:
|
return api.anal_type(t)
|
||||||
return api.anal_type(t)
|
|
||||||
|
|
||||||
|
|
||||||
def copy_method_to_another_class(
|
def copy_method_to_another_class(
|
||||||
|
|||||||
@@ -212,7 +212,11 @@ class AddManagers(ModelClassInitializer):
|
|||||||
# replace self type with new class, if copying method
|
# replace self type with new class, if copying method
|
||||||
if isinstance(sym.node, FuncDef):
|
if isinstance(sym.node, FuncDef):
|
||||||
helpers.copy_method_to_another_class(
|
helpers.copy_method_to_another_class(
|
||||||
new_cls_def_context, self_type=custom_manager_type, new_method_name=name, method_node=sym.node
|
new_cls_def_context,
|
||||||
|
self_type=custom_manager_type,
|
||||||
|
new_method_name=name,
|
||||||
|
method_node=sym.node,
|
||||||
|
original_module_name=base_manager_info.module_name,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ addopts =
|
|||||||
-s
|
-s
|
||||||
-v
|
-v
|
||||||
--cache-clear
|
--cache-clear
|
||||||
--mypy-ini-file=./mypy.ini
|
--mypy-ini-file=./mypy.ini.dev
|
||||||
--mypy-extension-hook=scripts.tests_extension_hook.django_plugin_hook
|
--mypy-extension-hook=scripts.tests_extension_hook.django_plugin_hook
|
||||||
|
|||||||
@@ -423,3 +423,22 @@
|
|||||||
class MyModel(models.Model):
|
class MyModel(models.Model):
|
||||||
|
|
||||||
objects = MyModelManager()
|
objects = MyModelManager()
|
||||||
|
|
||||||
|
- case: regression_manager_scope_foreign
|
||||||
|
main: |
|
||||||
|
from myapp.models import MyModel
|
||||||
|
reveal_type(MyModel.on_site) # N: Revealed type is "myapp.models.MyModel_CurrentSiteManager[myapp.models.MyModel]"
|
||||||
|
installed_apps:
|
||||||
|
- myapp
|
||||||
|
- django.contrib.sites
|
||||||
|
files:
|
||||||
|
- path: myapp/__init__.py
|
||||||
|
- path: myapp/models.py
|
||||||
|
content: |
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.sites.models import Site
|
||||||
|
from django.contrib.sites.managers import CurrentSiteManager
|
||||||
|
|
||||||
|
class MyModel(models.Model):
|
||||||
|
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
||||||
|
on_site = CurrentSiteManager()
|
||||||
|
|||||||
Reference in New Issue
Block a user