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

There should be an option to process TYPE_CHECKING #484

Open
1 task done
jolaf opened this issue Sep 8, 2024 · 13 comments
Open
1 task done

There should be an option to process TYPE_CHECKING #484

jolaf opened this issue Sep 8, 2024 · 13 comments

Comments

@jolaf
Copy link
Contributor

jolaf commented Sep 8, 2024

Things to check first

  • 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.

@agronholm
Copy link
Owner

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.

@agronholm
Copy link
Owner

This, for example, is a major effort for a run-time type checker which does not normally even see the if TYPE_CHECKING: blocks.

@jolaf
Copy link
Contributor Author

jolaf commented Sep 8, 2024

Would you consider becoming a maintainer for Typeguard?

I would happily, but unfortunately I'm not up to the task. :(

@jolaf
Copy link
Contributor Author

jolaf commented Sep 8, 2024

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.

@agronholm
Copy link
Owner

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.

@jolaf
Copy link
Contributor Author

jolaf commented Sep 8, 2024

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.

@JohannesK71083
Copy link
Contributor

@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?

@agronholm
Copy link
Owner

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.

@JohannesK71083
Copy link
Contributor

Can you give an code example for such a case?

@agronholm
Copy link
Owner

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)

@JohannesK71083
Copy link
Contributor

JohannesK71083 commented Feb 13, 2025

@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.

@agronholm
Copy link
Owner

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 annotations for 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?

@JohannesK71083
Copy link
Contributor

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).

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

No branches or pull requests

3 participants