Summary
The issue arises when using inspect.signature() or obj.__annotations__ to get a function signature as a string, resulting in a NameError. This error occurs because the type TracebackType is only defined within a TYPE_CHECKING block, which is not evaluated at runtime.
Root Cause
The root cause of this issue is that the TYPE_CHECKING block is only evaluated by static type checkers, not at runtime. As a result, the TracebackType is not defined when inspect.signature() or obj.__annotations__ is called, leading to a NameError. The causes of this issue include:
TYPE_CHECKINGblock not being evaluated at runtimeTracebackTypenot being defined outside theTYPE_CHECKINGblockinspect.signature()andobj.__annotations__requiring the type to be defined at runtime
Why This Happens in Real Systems
This issue can occur in real systems when using inspect.signature() or obj.__annotations__ to generate documentation or perform other tasks that require access to a function’s signature. The impacts of this issue include:
NameErrorexceptions being raised- Inability to generate accurate documentation
- Potential issues with other tools or libraries that rely on
inspect.signature()orobj.__annotations__
Real-World Impact
The real-world impact of this issue is that it can prevent developers from generating accurate documentation or performing other tasks that rely on inspect.signature() or obj.__annotations__. This can lead to:
- Inaccurate or incomplete documentation
- Issues with other tools or libraries that rely on
inspect.signature()orobj.__annotations__ - Increased development time and effort to work around the issue
Example or Code
from typing import TYPE_CHECKING
from inspect import signature
if TYPE_CHECKING:
from types import TracebackType
def some_function(tb_param: TracebackType) -> str:
return 'this is actually not important'
print(signature(some_function))
How Senior Engineers Fix It
Senior engineers can fix this issue by using the annotation_format=Format.STRING parameter when calling inspect.signature(), like this:
from inspect import signature, Format
print(signature(some_function, annotation_format=Format.STRING))
Alternatively, they can use string literals for types used only for annotations, or use from __future__ import annotations to enable postponed evaluation of annotations.
Why Juniors Miss It
Junior engineers may miss this issue because they:
- Are not familiar with the
TYPE_CHECKINGblock and its implications - Do not understand how
inspect.signature()andobj.__annotations__work - Do not recognize the importance of defining types at runtime
- Are not aware of the
annotation_format=Format.STRINGparameter or its use case - Do not consider the potential impacts of using
inspect.signature()orobj.__annotations__on their code.