-
-
Notifications
You must be signed in to change notification settings - Fork 453
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
Add failing test for Name "Sequence" is not defined
false positive
#1017
Add failing test for Name "Sequence" is not defined
false positive
#1017
Conversation
90449ea
to
56fbb15
Compare
56fbb15
to
7f26359
Compare
Reproduced in CI! https://github.com/christianbundy/django-stubs/runs/7057281103?check_suite_focus=true
(I'm using my fork to run CI since I think I have to have each workflow approved in this repo.) The problem was the |
Name "Sequence" is not defined
false positive
This reverts commit 1230b2a. My goal was a failing test, not a full fix. One step at a time.
Name "Sequence" is not defined
false positiveName "Sequence" is not defined
false positive
I think this is coming from t # Sequence?[str?]
t.name # 'Sequence'
module_name # 'django.db.models.query'
node # <mypy.nodes.SymbolTableNode object at 0x10ffd1720>
node.type # None
analyzed = api.anal_type(t)
analyzed # Any |
Crystal clear repro. https://github.com/christianbundy/django-stubs/actions/runs/2562518850 |
This seems to be happening when Looks like the problematic call is: bound_arg_type = bind_or_analyze_type(arg_type, semanal_api, original_module_name) |
Does the failing test ( (I think the only change that is needed to revert is to remove the |
It's interesting this error hasn't been caught by the
|
Maybe adding django-stubs/mypy_django_plugin/main.py Line 123 in 1a29ad4
|
I think the difference is that in the new test the model is used as |
I've tried reverting the changes like so: diff --git a/mypy_django_plugin/lib/helpers.py b/mypy_django_plugin/lib/helpers.py
index 1ce73fd..147eb99 100644
--- a/mypy_django_plugin/lib/helpers.py
+++ b/mypy_django_plugin/lib/helpers.py
@@ -369,8 +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 not None and node.type is not None:
- return node.type
+ if node is None:
+ return None
+ return node.type
return api.anal_type(t)
diff --git a/mypy_django_plugin/transformers/models.py b/mypy_django_plugin/transformers/models.py
index 17a2272..45d96a4 100644
--- a/mypy_django_plugin/transformers/models.py
+++ b/mypy_django_plugin/transformers/models.py
@@ -217,7 +217,6 @@ class AddManagers(ModelClassInitializer):
self_type=custom_manager_type,
new_method_name=name,
method_node=sym.node,
- original_module_name=base_manager_info.module_name,
)
continue
This fixes the failing test, but causes a failure for
I might've misunderstood, but I tried this and it didn't seem to fix the failing test. diff --git a/mypy_django_plugin/main.py b/mypy_django_plugin/main.py
index 6d3550d..d854509 100644
--- a/mypy_django_plugin/main.py
+++ b/mypy_django_plugin/main.py
@@ -126,8 +126,8 @@ class NewSemanalDjangoPlugin(Plugin):
return [self._new_dependency(self.django_context.django_settings_module)]
# for values / values_list
- if file.fullname == "django.db.models":
- return [self._new_dependency("mypy_extensions"), self._new_dependency("typing")]
+ if file.fullname.startswith("django.db.models"):
+ return [self._new_dependency("mypy_extensions"), self._new_dependency("typing"), self._new_dependency('typing_extensions')]
# for `get_user_model()`
if self.django_context.settings: |
I did a brief investigation and realised that cache matters. Adding This makes me believe that the suggestion @sobolevn has in #1017 (comment) is on the right track to hunt down the cause, that the issue appears depending on which order modules are analyzed. It seems that if Also, it seems that when copying from our 1st call site of django-stubs/mypy_django_plugin/transformers/managers.py Lines 281 to 288 in 926661a
While from our 2nd call site of django-stubs/mypy_django_plugin/transformers/models.py Lines 215 to 221 in 926661a
At least given our test cases and coverage. |
It also seems that, django-stubs/mypy_django_plugin/main.py Lines 165 to 170 in 926661a
I'm gonna try and move |
Nevermind, I misread |
That this depends on cache/resolution order matches with my impression as well. I had to use |
I've been digging into this issue this morning and I've kinda landed on the conclusion that the underlaying issue here really is a missing generic on All of the methods we copy to the new manager from the queryset are already defined on the manager (in the stubs), so the only reason we need to copy them is to fix the return type. That shouldn't be needed, as those methods should be correctly typed on the manager based on a generic queryset. I haven't figured out if it's actually possible to type this correctly yet. I'd expect we need something like As an alternative I think we might be able to correct the return type of these methods using the Does this seem reasonable to you @flaeppe and @sobolevn? Edit: Actually this example works in mypy, it was pyright that was complaining: from typing import Generic, TypeVar
class Model:
pass
M = TypeVar("M", bound=Model)
class QuerySet(Generic[M]):
def get(self) -> M:
pass
QS = TypeVar("QS", bound=QuerySet)
class Manager(Generic[M, QS[M]]):
def get_queryset(self) -> QS:
pass
def get(self) -> M:
pass
m = Manager[Model, QuerySet[Model]]()
reveal_type(m.get_queryset().get()) # note: Revealed type is "something.Model"
reveal_type(m.get()) # note: Revealed type is "something.Model" |
Yes, anything is better than directly coping methods 👍 |
I gave the generics approach a quick try and immediately hit limitations, so that doesn't really appear to be supported by mypy. Guess it might be worth an issue in mypy, but this seems like a limitation of the typing system in Python, so I'm not sure if that's the right place for it. So I think the |
I think there's at least one, typing (or even reveal_type(MyModel.objects.select_for_update) But it will be called when the method is invoked, e.g. MyModel.objects.select_for_update() |
The same seems to apply for |
Hmm, yeah 😞 I guess an option is to go the same route as for custom queryset methods. Ie add the methods attributes with type |
Pretty sure I managed to fix this in #1028. I copied over the test setup from here, included my initial reproducer and changed the logic for resolving all queryset methods to be based on the attribute approach already used for custom queryset methods. |
Problem: There seems to be a bug in this code, but the current tests don't fail.
Solution: Add a new failing test.
Fixes:
#709 (comment)#1022