Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
7 changes: 7 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -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
Expand Down
30 changes: 30 additions & 0 deletions mypy.ini.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Configuration file to use during development
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please drop a few lines about why do we need this file?


# 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
9 changes: 4 additions & 5 deletions mypy_django_plugin/lib/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,10 @@ 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
return node.type
else:
return api.anal_type(t)
if node is not None and node.type is not None:
return node.type

return api.anal_type(t)


def copy_method_to_another_class(
Expand Down
6 changes: 5 additions & 1 deletion mypy_django_plugin/transformers/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,11 @@ def create_new_model_parametrized_manager(self, name: str, base_manager_info: Ty
# 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

Expand Down
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
19 changes: 19 additions & 0 deletions tests/typecheck/managers/test_managers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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()