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
|
||||
|
||||
- name: Run tests
|
||||
run: pytest
|
||||
run: pytest --mypy-ini-file=mypy.ini
|
||||
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -70,6 +70,12 @@ To execute the unit tests, simply run:
|
||||
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.
|
||||
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]
|
||||
allow_redefinition = 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,10 +369,9 @@ def bind_or_analyze_type(t: MypyType, api: SemanticAnalyzer, module_name: Option
|
||||
That should hopefully give a bound type."""
|
||||
if isinstance(t, UnboundType) and module_name is not None:
|
||||
node = api.lookup_fully_qualified_or_none(module_name + "." + t.name)
|
||||
if node is None:
|
||||
return None
|
||||
if node is not None and node.type is not None:
|
||||
return node.type
|
||||
else:
|
||||
|
||||
return api.anal_type(t)
|
||||
|
||||
|
||||
|
||||
@@ -212,7 +212,11 @@ class AddManagers(ModelClassInitializer):
|
||||
# replace self type with new class, if copying method
|
||||
if isinstance(sym.node, FuncDef):
|
||||
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
|
||||
|
||||
|
||||
@@ -7,5 +7,5 @@ addopts =
|
||||
-s
|
||||
-v
|
||||
--cache-clear
|
||||
--mypy-ini-file=./mypy.ini
|
||||
--mypy-ini-file=./mypy.ini.dev
|
||||
--mypy-extension-hook=scripts.tests_extension_hook.django_plugin_hook
|
||||
|
||||
@@ -423,3 +423,22 @@
|
||||
class MyModel(models.Model):
|
||||
|
||||
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