Skip to content
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

AssertionError: Cannot find X for Y.X (incremental with warm cache) #2535

Closed
gvanrossum opened this issue Dec 7, 2016 · 16 comments
Closed

Comments

@gvanrossum
Copy link
Member

gvanrossum commented Dec 7, 2016

This is similar to #2451 but the cause is different. I haven't boiled it down yet but the clue seems to be there's a NamedTuple definition inside a [EDITs from here:] for-loop inside a method. And another report where there's a namedtuple inside a method.

@gvanrossum gvanrossum self-assigned this Dec 7, 2016
@gvanrossum
Copy link
Member Author

gvanrossum commented Dec 8, 2016

OK, simple repro: run mypy -i main.py ntcrash.py twice (without touching any files in between) where:

  • ntcrash.py:
from typing import NamedTuple

class C:
    def f(self) -> None:
        A = NamedTuple('A', [('x', int), ('y', int)])
  • main.py:
import ntcrash

@gvanrossum
Copy link
Member Author

The problem is in the code that @kirbyfan64 fixed -- it's still broken in this case due to the peculiarities of how namedtuple classes are bootstrapped in the mypy code.

@gvanrossum gvanrossum removed their assignment Dec 8, 2016
@gvanrossum gvanrossum added this to the 0.4.x milestone Dec 8, 2016
@elazarg
Copy link
Contributor

elazarg commented Dec 10, 2016

Is this the 5th item in #2090 - "handle locally-defined namedtuple"?

@gvanrossum
Copy link
Member Author

Yes, that's right. I'm not sure how to resolve it. Maybe the "qualified name" should be similar to what we use at runtime? E.g. with this code

class C:
    def f(self):
        class D: pass
        return D()
d = C().f()
print(d.__class__.__qualname__)

the output is C.f.<locals>.D. Combined with the module name that might work? But we'd have to introduce a namespace for the method.

Thinking aloud, another possibility would be to give the inner class a synthetic qualified name starting with a digit, e.g. C.0001_f_D (plus module prefix).

@gvanrossum
Copy link
Member Author

(The key requirement here being simply that whatever the qualified name is can be found by the lookup method in fixup.py. We may have to modify both the qualified name and the lookup function to deal with the special case.)

@gvanrossum
Copy link
Member Author

I'm going crazy. I can only make my repro "work" (i.e. cause the AssertionError) if I make main.py import a non-existent symbol from ntcrash, e.g.from ntcrash import nope.

@elazarg
Copy link
Contributor

elazarg commented Dec 11, 2016

It's unrelated to the content. You should touch main.py before running mypy.

@gvanrossum
Copy link
Member Author

That doesn't work for me. I delete the cache before starting. I really do have import something non-existing from ntcrash into main.

gvanrossum pushed a commit that referenced this issue Dec 11, 2016
@gvanrossum
Copy link
Member Author

Here's a test with the repro: ead98b3

@gvanrossum
Copy link
Member Author

Note there are other variants, e.g.

class C:
    def a(self) -> None:
        class D:
            def f(self) -> None:
                A = NamedTuple('A', [('x', int), ('y', int)])

@elazarg
Copy link
Contributor

elazarg commented Dec 11, 2016 via email

@gvanrossum
Copy link
Member Author

This is a tremendously fertile bug breeding area. :-( See the gyrations in the PR where I'm attempting to fix this, #2553. See also #2559, inspired by some test cases there.

@gvanrossum gvanrossum changed the title AssertionError: Cannot find X for Y.X AssertionError: Cannot find X for Y.X (incremental with warm cache) Dec 13, 2016
gvanrossum added a commit that referenced this issue Dec 14, 2016
@ilevkivskyi
Copy link
Member

The problem is still there if the code in ntcrash.py in the original example is more deeply nested:

from typing import NamedTuple

class C:
    def f(self) -> None:
        class D:
            class E:
                def g(self) -> None:
                    A = NamedTuple('A', [('x', int), ('y', int)])
                    self.a = A(1, 1)
        self.c = D.E().a

This could be easily fixed by always storing "anonymous" named tuples in globals.
I understand this situation is super rare, just wanted to mention this here, maybe at some someone will decide to fix this very minor thing.

@JukkaL
Copy link
Collaborator

JukkaL commented Mar 1, 2017

@ilevkivskyi Can you create a new issue for the remaining problem, since otherwise it's easy to miss? We can tag it as low priority, but I'd like to keep track of crash bugs.

@ilevkivskyi
Copy link
Member

@JukkaL OK, here it is #2931

@JukkaL
Copy link
Collaborator

JukkaL commented Mar 1, 2017

@ilevkivskyi Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants