Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mypy explicit type hint in quotes still gives not defined error

I am trying to do the following thing:

self.sender = None # type: 'Node'

I can't import Node because I would get an cycle. So I write it in quotes like mentioned here http://mypy.readthedocs.io/en/latest/common_issues.html#import-cycles But I still get the following error

error: Name 'Node' is not defined

Is there any solution for this?

Thanks!

like image 717
stefanhoelzl Avatar asked Jun 09 '16 19:06

stefanhoelzl


1 Answers

Short answer, you need to include the module name of the class, and you need to import that module within some unreachable code, like this:

if False:
    # for forward-reference type-checking:
    import mymodule

class MyClass(object):
    def __init__(self):
        self.sender = None  # type: mymodule.Node

In order to understand why this is required (and why it works), you must first realize that mypy is doing static code analysis. That means it's not importing your modules, it's parsing and analyzing text read from your module files.

When the module above is imported, the import mymodule line will never run and will therefore avoid your cyclical import, but it is still available for mypy to parse. This is how mypy is able to resolve the reference to mymodule.Node during analysis.

For the sake of completeness, I should mention that it is not required that you use the module name, you can use any name that won't cause a conflict during parsing:

if False:
    from mymodule import Node

class MyClass(object):
    def __init__(self):
        self.sender = None  # type: Node

Also note that you do not need to use quotes around type names that appear in comments. That is only necessary when the type annotation appears directly in a python object. Here are some scenarios where that might happen:

from typing import Optional, NamedTuple
if False:
    from mymodule import Node

NodeInfo = NamedTuple('NodeInfo', [('node', 'Node'), ('info', dict)])

class MyClass(object):
    def __init__(self, sender: Optional['Node'] = None):
        self.sender = sender
like image 106
chadrik Avatar answered Sep 27 '22 19:09

chadrik