-
-
Notifications
You must be signed in to change notification settings - Fork 454
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix manager types scope #991
Conversation
mypy.ini
Outdated
@@ -2,7 +2,8 @@ | |||
allow_redefinition = True | |||
check_untyped_defs = True | |||
ignore_missing_imports = True | |||
incremental = True | |||
# Incremental mode causes false-negatives | |||
incremental = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had this flag to support mypy in incremental mode as the first-class-citizen. It is important for:
- large projects that use
--incremental
to speed up their checks - IDEs that use mypy plugins
I am not sure that removing it is a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, okay. Reverted this and added explicit mention in CONTRIBUTING.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please post unexpected results here? What were they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unexpected result was quite simple: I started from this regression test and confirmed that it fails. Then I attempted first fix (added module_name
) and rerun test suite - this reg.test passed as expected and two others failed. Then I reverted everything and... got fully passing test suite, including reg.test - which is obviously wrong. Removing mypy cache helped to make reg. test fail again, so incremental mode is harmful during development. Maybe we should have different configs for CI and local development?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should have different configs for CI and local development?
Yes, this is a good option!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -0,0 +1,21 @@ | |||
# Configuration file to use during development |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work!
In multiple of our repos this commit introduces a phantom warning, saying |
Same here. Will investigate this tomorrow. I'm surprised it was not caught by test suite. UPD: this |
Yeah, I found that as well, but it doesn't help that much. I'm 99% sure the phantom warning comes from calling |
Yeah, I think @ljodal is right here. The problem is most likely running I can't track down where in mypy the error will be emitted from. But supposedly from somewhere in: https://github.com/python/mypy/blob/203bd64d8c14e8ddbed7911eb6f8f8aa61d728de/mypy/semanal.py#L639 Be aware of that the code emitting the error is from the other call site of django-stubs/mypy_django_plugin/transformers/managers.py Lines 281 to 288 in 1a29ad4
Half side note: IMO that It's just that, runtime, that's kind of what Django does. "Only" thing being that the class is dynamically created.. |
The problem with doing this through MRO, other than it not matching the actual runtime types, is that Django is skipping some methods when copying/redefining queryset methods on managers. So if we simply say that the generated manager inherits from the queryset we would expose methods that doesn't actually exist on the manager at runtime. Methods can be explicitly marked as skipped or be skipped because they're already implemented by the manager: https://github.com/django/django/blob/b2eff16806057095c7dd3daa9402ad615e51627f/django/db/models/manager.py#L95-L102 I'm wondering if we're doing something wrong further upstream. I'm really curious about why this "binding" stage is required and if we should rather be deferring to the next mypy iteration at some point maybe 🤔 |
I'm pretty sure we're not honoring skipping methods currently: django-stubs/mypy_django_plugin/transformers/managers.py Lines 215 to 288 in 926661a
But I see your point with the difficulty of resolving that anyways, with the MRO. Worth noting is also that the only copied methods through django-stubs/mypy_django_plugin/transformers/managers.py Lines 249 to 251 in 926661a
Methods coming from the queryset are resolved differently: django-stubs/mypy_django_plugin/transformers/managers.py Lines 215 to 233 in 926661a
The queryset approach was implemented to resolve exactly these kind of "phantom errors", but for custom queryset methods, a while back through #820 (initial issue in #709) |
Oh, that's a very good point. I was planning on testing out the same plug-in callback logic for all queryset methods to see if that resolved #958 (which is a similar "something is wrong with the types after copying" issue), but never got around to that. That would probably be worth a try to see if it maybe resolves both issues |
I think you're slightly off here, methods from custom querysets are not copied, methods from the default |
Fixed wrong scope of managers methods when manager is imported from another file.
On master branch the following is enough to reproduce the issue:
It results in weird
mypy
error:The changes are self-explanatory, but here's a short explanation:
original_module_name
, two other tests began to fail. It happened becauseapi.anal_type
was expected, but ran only ifmodule_name is None
. So we want to call it even if module name was given, but only if initial solution (withlookup_fully_qualified
) fails to return something meaningful.Related issues
This issue was discovered in this SO question.