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

Internal Error: maptype.py: AttributeError: attribute 'type_vars' of 'TypeInfo' undefined #7806

Closed
sebastian-philipp opened this issue Oct 28, 2019 · 8 comments · Fixed by #12023

Comments

@sebastian-philipp
Copy link

  • Are you reporting a bug, or opening a feature request?

Bug

  • Please insert below the code you are checking with mypy,
    or a mock-up repro if the source is private. We would appreciate
    if you try to simplify your case to a minimal repro.

Hints on how to simply create a minimal example are appreciated.

  • What is the actual behavior/output?
dashboard/plugins/plugin.py: note: In member "get_options" of class "SimplePlugin":
dashboard/plugins/plugin.py:20: error: "SimplePlugin" has no attribute "OPTIONS"
dashboard/plugins/plugin.py:24: error: INTERNAL ERROR -- Please try using mypy master on Github:
https://mypy.rtfd.io/en/latest/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.740
Traceback (most recent call last):
  File "mypy/checkexpr.py", line 3603, in accept
  File "mypy/nodes.py", line 1484, in accept
  File "mypy/checkexpr.py", line 1887, in visit_member_expr
  File "mypy/checkexpr.py", line 1899, in analyze_ordinary_member_access
  File "mypy/checkmember.py", line 117, in analyze_member_access
  File "mypy/checkmember.py", line 134, in _analyze_member_access
  File "mypy/checkmember.py", line 210, in analyze_instance_member_access
  File "mypy/checkmember.py", line 359, in analyze_member_var_access
  File "mypy/checkmember.py", line 517, in analyze_var
  File "mypy/maptype.py", line 20, in map_instance_to_supertype
AttributeError: attribute 'type_vars' of 'TypeInfo' undefined
dashboard/plugins/plugin.py:24: : note: use --pdb to drop into pdb
  • What are the versions of mypy and Python you are using?

0.740

  • Do you see the same issue after installing mypy from Git master?

Not checked yet.

  • What are the mypy flags you are using? (For example --strict-optional)
[mypy]
strict_optional = True
no_implicit_optional = True
ignore_missing_imports = True
warn_incomplete_stub = True
check_untyped_defs = True
show_error_context = True
  • Reproducable with
git clone --depth 1 --single-branch --branch mypy-mgr_module https://github.com/sebastian-philipp/ceph.git
cd ceph/src 
script/run_mypy.sh
@JukkaL
Copy link
Collaborator

JukkaL commented Oct 28, 2019

I was able to find a small example that results in a similar crash:

# pkg/__init__.py
mgr = object()
# pkg/sub/__init__.py
# (empty)
# pkg/sub/m.py
class C:
    from .. import mgr

    def f(self) -> None:
        return self.mgr.whatever()
$ mypy --show-traceback pkg/sub/m.py
t/pkg/sub/m.py:5: error: INTERNAL ERROR -- Please try using mypy master on Github:
https://mypy.rtfd.io/en/latest/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.750+dev.fdcbb74b2e01f6afd0549da6375a66aab839fd9a
Traceback (most recent call last):
  ...
  File "/Users/jukka/src/mypy/mypy/build.py", line 164, in build
    result = _build(sources, options, alt_lib_path, flush_errors, fscache, stdout, stderr)
  File "/Users/jukka/src/mypy/mypy/build.py", line 230, in _build
    graph = dispatch(sources, manager, stdout)
  File "/Users/jukka/src/mypy/mypy/build.py", line 2567, in dispatch
    process_graph(graph, manager)
  File "/Users/jukka/src/mypy/mypy/build.py", line 2876, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/Users/jukka/src/mypy/mypy/build.py", line 2975, in process_stale_scc
    graph[id].type_check_first_pass()
  File "/Users/jukka/src/mypy/mypy/build.py", line 2071, in type_check_first_pass
    self.type_checker().check_first_pass()
  File "/Users/jukka/src/mypy/mypy/checker.py", line 289, in check_first_pass
    self.accept(d)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 396, in accept
    stmt.accept(self)
  File "/Users/jukka/src/mypy/mypy/nodes.py", line 927, in accept
    return visitor.visit_class_def(self)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 1707, in visit_class_def
    self.accept(defn.defs)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 396, in accept
    stmt.accept(self)
  File "/Users/jukka/src/mypy/mypy/nodes.py", line 992, in accept
    return visitor.visit_block(self)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 1958, in visit_block
    self.accept(s)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 396, in accept
    stmt.accept(self)
  File "/Users/jukka/src/mypy/mypy/nodes.py", line 668, in accept
    return visitor.visit_func_def(self)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 721, in visit_func_def
    self._visit_func_def(defn)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 725, in _visit_func_def
    self.check_func_item(defn, name=defn.name())
  File "/Users/jukka/src/mypy/mypy/checker.py", line 787, in check_func_item
    self.check_func_def(defn, typ, name)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 961, in check_func_def
    self.accept(item.body)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 396, in accept
    stmt.accept(self)
  File "/Users/jukka/src/mypy/mypy/nodes.py", line 992, in accept
    return visitor.visit_block(self)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 1958, in visit_block
    self.accept(s)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 396, in accept
    stmt.accept(self)
  File "/Users/jukka/src/mypy/mypy/nodes.py", line 1128, in accept
    return visitor.visit_return_stmt(self)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 2981, in visit_return_stmt
    self.check_return_stmt(s)
  File "/Users/jukka/src/mypy/mypy/checker.py", line 3014, in check_return_stmt
    s.expr, return_type, allow_none_return=allow_none_func_call))
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 3599, in accept
    typ = self.visit_call_expr(node, allow_none_return=True)
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 264, in visit_call_expr
    return self.visit_call_expr_inner(e, allow_none_return=allow_none_return)
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 313, in visit_call_expr_inner
    callee_type = get_proper_type(self.accept(e.callee, type_context, always_allow_any=True))
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 3603, in accept
    typ = node.accept(self)
  File "/Users/jukka/src/mypy/mypy/nodes.py", line 1484, in accept
    return visitor.visit_member_expr(self)
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 1887, in visit_member_expr
    result = self.analyze_ordinary_member_access(e, is_lvalue)
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 1898, in analyze_ordinary_member_access
    original_type = self.accept(e.expr)
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 3603, in accept
    typ = node.accept(self)
  File "/Users/jukka/src/mypy/mypy/nodes.py", line 1484, in accept
    return visitor.visit_member_expr(self)
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 1887, in visit_member_expr
    result = self.analyze_ordinary_member_access(e, is_lvalue)
  File "/Users/jukka/src/mypy/mypy/checkexpr.py", line 1902, in analyze_ordinary_member_access
    in_literal_context=self.is_literal_context())
  File "/Users/jukka/src/mypy/mypy/checkmember.py", line 117, in analyze_member_access
    result = _analyze_member_access(name, typ, mx, override_info)
  File "/Users/jukka/src/mypy/mypy/checkmember.py", line 134, in _analyze_member_access
    return analyze_instance_member_access(name, typ, mx, override_info)
  File "/Users/jukka/src/mypy/mypy/checkmember.py", line 210, in analyze_instance_member_access
    return analyze_member_var_access(name, typ, info, mx)
  File "/Users/jukka/src/mypy/mypy/checkmember.py", line 359, in analyze_member_var_access
    return analyze_var(name, v, itype, info, mx, implicit=implicit)
  File "/Users/jukka/src/mypy/mypy/checkmember.py", line 517, in analyze_var
    itype = map_instance_to_supertype(itype, var.info)
  File "/Users/jukka/src/mypy/mypy/maptype.py", line 20, in map_instance_to_supertype
    if not superclass.type_vars:
  File "/Users/jukka/src/mypy/mypy/nodes.py", line 2629, in __getattribute__
    raise AssertionError(object.__getattribute__(self, 'msg'))
AssertionError: Var is lacking info
t/pkg/sub/m.py:5: : note: use --pdb to drop into pdb

This traceback is a bit different since it's from a non-compiled mypy.

@vemel
Copy link

vemel commented Oct 30, 2019

I prepared a PR but it lacks unit tests.

@JukkaL As far as I understand, we are getting FakeInfo for this attribute that cannot be handled by mypy/checkmember.py. With this fix, FakeInfo.__getattribute__ handles '__class__', 'fullname', '_fullname', 'type_vars' as regular attributes inherited from TypeInfo.

@vemel
Copy link

vemel commented Oct 31, 2019

Does it make more sense to remove custom __getattribute__ and just get a regular AttributeError instead? I do not see how it could break existing functionality.

@Michael0x2a
Copy link
Collaborator

@vemel -- I think the better fix here is to figure out why the FakeInfo is sneaking past the initial semantic analysis phase. If everything is working, every FakeInfo ought to be replaced by a legitimate TypeInfo by the time we make it to the type-checking phase and actually start using the object -- see FakeInfo's docstring for more details about this.

Removing __getattribute__ won't work here, since FakeInfo subclasses TypeInfo. This means it would by default have access to the attributes when we really want to be blacklisting them all instead.

To put it another way, what FakeInfo is doing is breaking the Liskov substitution principle to the fullest extent possible while still remaining a subclass of TypeInfo. This technique lets us defer distinguishing between ready and not-ready TypeInfos to runtime: it turns out attempting to make this distinction at the type level (e.g. scatter around "if this object is a ready instance..." checks) ends up making the code pretty messy and difficult to maintain.

@vemel
Copy link

vemel commented Oct 31, 2019

should there be a class for RealTypeInfo, that checkmember functions should expect? this will add a level of type safety

@JukkaL
Copy link
Collaborator

JukkaL commented Nov 1, 2019

should there be a class for RealTypeInfo

I don't think that there's a simple way to do this, without littering the code with many runtime type checks.

@ChastinaLi
Copy link

ChastinaLi commented Mar 15, 2021

Ran into this issue which completely breaks our entire linting pipeline. Does anybody have a workaround for this?

@sebastian-philipp
Copy link
Author

sebastian-philipp commented Mar 15, 2021

#type: ignore on the head of the file that workarounds this issue

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