There should be an option to process TYPE_CHECKING
Things to check first
- [X] I have searched the existing issues and didn't find my feature already requested there
Feature description
It would be nice for typeguard to actually process what's inside the if TYPE_CHECKING blocks, actually importing the referenced modules etc.
It would be nice to have an option to turn on this behavior.
Use case
That's not how an app would work without typeguard, but that would allow to check the app for type correctness more thoroughly.
Would you consider becoming a maintainer for Typeguard? I don't have the bandwidth to keep up the development, as I'm mired in developing many other projects.
This, for example, is a major effort for a run-time type checker which does not normally even see the if TYPE_CHECKING: blocks.
Would you consider becoming a maintainer for Typeguard?
I would happily, but unfortunately I'm not up to the task. :(
run-time type checker which does not normally even see the
if TYPE_CHECKING:blocks
You mean they're somehow excluded from the source tree when importing the module?
Is it possible to just set TYPE_CHECKING to True when importing the module?
I was thinking that you're making a special effort to look into TYPE_CHECKING blocks to make sure the annotations mentioning things imported there are not producing errors. If TYPE_CHECKING is somehow set to True, those efforts may be just turned off.
You mean they're somehow excluded from the source tree when importing the module?
A run-time type checker just sees what's there at run time, it doesn't normally inspect the source code, and this isn't even always possible (like in the REPL). Normally, if TYPE_CHECKING is set to False, which it is always at run time, no code in the block is executed so whatever imports you have there aren't done.
Typeguard goes out of its way to parse and modify the source code, but that comes with an additional, massive increase to complexity and a performance hit that some users are unhappy with.
Is it possible to just set TYPE_CHECKING to True when importing the module?
That's not a viable option. In these blocks, it's customary to do things that don't work at all at run time, like importing Typeshed types.
That's not a viable option.
Well, everything I talk about here is only an option.
It seems to me it would be nice if a user could choose, to execute TYPE_CHECKING blocks or not, in their particular case.
@jolaf
Can you give an example when this would be useful?
My understanding is that inside TYPE_CHECKING should only be imports that can't happen at runtime because of circular imports (because it is imported at runtime at that point anyways). So typeguard should be able to check all annotations at runtime without evaluating the TYPE_CHECKING blocks or am I missing something?
People (including yours truly) use TYPE_CHECKING for different purposes. One useful purpose is to avoid unnecessary imports, even if they would work at run time.
Can you give an code example for such a case?
Can you give an code example for such a case?
Easy:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Sequence
def join(a: Sequence[int], b: Sequence[int]) -> Sequence[int]:
return list(a) + list(b)
@agronholm
Yes, that works (currently), but it only works because of from __future__ import annotations and violates the condition that "annotations need to be syntactically valid Python expressions [...] [and] can only use names present in the module scope [at runtime]" (PEP 563).
from __future__ import annotations is not intended for such use but only to solve "forward references" and that type hints are evaluated (and cost evaluation time) (PEP 563).
When using from __future__ import annotations for its intended use, then evaluating TYPE_CHECKING blocks would bring no further information.
Um, how are these not syntactically valid Python expressions? And yes, I know what the future import is for and how it works.
When using
from __future__ import annotationsfor its intended use, then evaluating TYPE_CHECKING blocks would bring no further information.
How else would Typeguard be able to check passed arguments against these annotations?
Yes, you're right.
I misinterpreted the PEP because I was taught that you should use TYPE_CHECKING blocks only if you have to (import cycles). In that case the object would always be imported somewhere (in at least one module) and you could get the information from there.
But after reading the PEP again very carefully I now understand that you are also allowed (by PEP) to use it your way (to optimize or for other purposes).