Underscore for type-check only items?
Just a random thought: When we add classes or type aliases to stubs that aren't available at runtime, but could be useful for users as well (by using if TYPE_CHECKING:), we currently prefix them with an underscore. This has two disadvantages:
- Linters and IDEs (as well as the linter in my brain) often mark them as "using a private item from an external module". This isn't really the case here as we support the use of these items during type checking.
- It doesn't really communicate the fact that the item is available during type-check only.
Maybe it would make sense to come up with another convention to mark these type-check only? The (admittedly failed) @type_check_only decorator doesn't really help in this situation, as it marks the items only when defining them, not when importing them. It also doesn't work with type aliases.
I think we need to make sure we continue to clearly signal "danger" to users with these aliases. Importing things under if TYPE_CHECKING blocks can be useful, but it's not something typing beginners will necessarily know about. I think it would be a bad outcome if IDEs and autocomplete tools started recommending to users that they imported apparently public-API aliases etc., with neither the tool nor the user realising that the aliases weren't available at runtime.
So: I'm open to changes, but think we need to be cautious and make sure we don't regress on user experience for people who don't know about typeshed etc. :)
I also think stubtest could help us here for the @type_check_only decorator (even though it's limited, I also wish some decorators in Python worked on more than just callables): https://github.com/python/mypy/issues/15146
Not sure if I like this idea or not, but I'll share it anyway to get it out:
If you place all non-runtime typing into a single private module in a package, type-checkers may warn about private module usage, and may warn about the module not existing at runtime (reportMissingModuleSource in pyright).
Example usage from AutoSplit using pywin32 (this is a special case module for types defined in the C extension but never exposed to the Python interface):
If you use a standard name (like _type_check_only or _typeshed_type_check_only), you can also configure tooling to ignore specific rules in there with per-file/per-folder ignore (like Y047)
Might cause a lot of cross-reference, and specialized aliases/Protocols/etc won't live in the only place they're used. Some context might be lost.
Currently we have _typeshed. What about expanding that? I'd suggest that for a given stdlib module foo we should import from _typeshed.foo while for a third-party module bar we should import from bar._typeshed.
My thinking there is that most stdlib modules are single-file, and it'd be a pain to convert them all to a directory just for this. But on the other hand, putting all the third-party modules under _typeshed.* would be breaking the context more than necessary, and maybe be a little crowded