PEP 781: Make ``TYPE_CHECKING`` a built-in constant

It is not entirely clear what is meant by “runtime typing” or what exactly constitutes it being “broken”. If the expectation is that it should always be possible to evaluate all type annotations at runtime then that can never fully work and so in some sense runtime typing will always be broken.

Here is a simple example:

if TYPE_CHECKING:
    from optional_dependency import NotInstalledType

class A:
    def func(...) -> NotInstalledType
         import optional_dependency
         return optional_dependency.func(...)

The type annotation here refers to a type that may not exist at runtime if the package that contains it is not installed. No alternative spelling of TYPE_CHECKING, type import etc will make it possible to evaluate that annotation reliably at runtime.

Does the class A “break runtime typing” if any one of its methods has an annotation that cannot be evaluated? If so then runtime typing is a somewhat misguided concept and there needs to be some understanding of what its limitations are rather than an expectation that it could ever be made to work in general.

I think most of the time what people refer to as runtime typing does not really require that every single annotation be evaluated at runtime. An important exception though is the sphinx autodoc case which really does need to get every single annotation.

The only way this can be made to work reliably in general for sphinx is to get the annotations statically rather than trying to extract them at runtime. Consider e.g. this case where the docs should say that a function returns a special type MPZ but that type never actually exists at runtime. Basically sphinx needs to get the annotations the same way that a static type checker would. Maybe sphinx could literally use some existing static type checker to do this rather than setting TYPE_CHECKING=True at runtime which doesn’t generally work.

3 Likes