Reputation: 2965
I've been struggling with strange situations where mypy is happy, but python crashes when I run the code. Here's an issue I'm having with generics. I have two files in the same directory. When I run python3 in sample_parser.py
, I get the following error:
Traceback (most recent call last):
File "/Users/joe/repos/ut-norm-james/so_generics/sample_parser.py", line 8, in <module>
class SampleParser(LookaheadParser[str]):
NameError: name 'LookaheadParser' is not defined
Here's lookahead_parser.py
:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import TypeVar, Generic, Optional, Callable
_T = TypeVar("_T")
StateFunc = Callable[[_T], Callable]
class LookaheadParser(Generic[_T]):
def __init__(self):
self._token_index: int = 0
self._tokens: list[_T] = []
self._state: StateFunc
def _parse(self) -> None:
while self._token_index < len(self._tokens):
self._state = self._state(self._tokens[self._token_index])
self._token_index += 1
def _lookahead(self, offset: int) -> Optional[_T]:
prospective_index = self._token_index + offset
if prospective_index < len(self._tokens):
return self._tokens[prospective_index]
return None
def _advance(self, offset: int) -> None:
self._token_index += offset
Here's sample_parser.py
:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .lookahead_parser import LookaheadParser, StateFunc
class SampleParser(LookaheadParser[str]):
def __init__(self, raw_text: str):
self._raw_text = raw_text
self._state = self._state_first
def parse(self) -> None:
self._parse()
def _state_first(self, token: str) -> StateFunc:
pass # stub
if __name__ == "__main__":
pass # stub
I'm running Python 3.9.6, but it was also happening in 3.9.5. The problem occurs whether I use _T
or T
, in case you're looking askance at that. mypy itself is not reporting any problems.
Upvotes: 0
Views: 573
Reputation: 70267
You only import lookahead_parser
if TYPE_CHECKING
is true. That variable is false at runtime, so the module never gets loaded. Just remove the if TYPE_CHECKING:
part and do the import unconditionally.
from .lookahead_parser import LookaheadParser, StateFunc
Upvotes: 2