Example
Given the file ./mylib/minimalistic_repro.py
class Foo:
def __init__(self, param):
self.param = param
class Bar:
def __init__(self, param):
self.param = param
def foobar(par1, par2):
return par1.param + par2.param
and its stub ./mylib/minimalistic_repro.pyi
from typing import TypeAlias
FooBar: TypeAlias = Foo | Bar
class Foo:
param: int
def __init__(self, param: int) -> None: ...
class Bar:
param: int
def __init__(self, param: int) -> None: ...
def foobar(par1: FooBar, par2: FooBar) -> int: ...
Note the type alias on the third line: FooBar: TypeAlias = Foo | Bar
mypy --strict mylib
, flake8 mylib
and ruff check --select E,F,B,SIM
all pass.
When running stubtest however:
python -m mypy.stubtest mylib
I get the following error:
error: mylib.minimalistic_repro.FooBar is not present at runtime
…
My current workaround is to use an allowlist (stubtest --generate-allowlist
).
Question(s)
● Is there a “better” way to avoid this “error”? / …
● … Am I doing something fundamentally wrong? …
● … and if not: Might this be worth a feature request?
Other approaches
● Of course I could declare
def foobar(par1: Foo | Bar, par2: Foo | Bar)
,
but my actual task (writing type hints for a third party pypi package) requires a union of up to 18 types.
● I got the above example to run with stubtest
by placing the FooBar type alias definition in a .py file (tp_aliases.py) and then reimporting. This approach failed to work in the case of with my actual pypi package type hinting task (tp_aliases.py is not part of the pypi package).
stubtest
is complaining because it thinks your FooBar
is a public API symbol, which might cause type checkers/IDE autocomplete to make incorrect assumptions and suggestions.
The "correct" way to fix it is to make it private; that is, precede the name with an underscore:
_FooBar: TypeAlias = Foo | Bar
def foobar(par1: _FooBar, par2: _FooBar) -> int: ...
For classes and functions, you can alternatively use typing.type_check_only
:
# type_check_only is not available at runtime and can only be used in stubs
from typing import type_check_only
@type_check_only
def this_function_is_not_available_at_runtime() -> None: ...
@type_check_only
class AndSoDoesThisClass: ...
There's also the command line option --ignore-missing-stub
which will suppress all errors of this kind.