We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← True Parallelism and the Runtime step 9 of 18
Typing Multiprocessing: Where the Annotations Lie to You
A --strict codebase that touches multiprocessing usually ends up with a
scatter of # type: ignore at the most dangerous boundary in the program.
Almost all of them come from one mistake, and knowing the right import removes
them.
Why multiprocessing.Lock is not a type
def acquire(lock: multiprocessing.Lock) -> None: ...
error: Variable "multiprocessing.Lock" is not valid as a type [valid-type]
At runtime, type(multiprocessing.Lock) is method. The names exported
from the multiprocessing package are autogenerated bound methods of the
default context object, not classes. The classes live in submodules:
| You reached for | The type actually is |
|---|---|
multiprocessing.Lock / Event / Semaphore / Condition / Barrier |
multiprocessing.synchronize.* |
multiprocessing.Queue / JoinableQueue / SimpleQueue |
multiprocessing.queues.* |
multiprocessing.Value / Array |
multiprocessing.sharedctypes.* |
multiprocessing.Pool |
multiprocessing.pool.Pool |
Manager().dict() |
multiprocessing.managers.DictProxy |
Pipe() ends |
multiprocessing.connection.Connection |
The trap mypy does not catch
def enqueue(q: multiprocessing.Queue[int]) -> None: ...
This passes --strict. typeshed declares Queue generic, so the checker
is satisfied. Then, at runtime:
>>> typing.get_type_hints(enqueue)
TypeError: 'method' object is not subscriptable
Because multiprocessing.Queue is a bound method, and methods are not
subscriptable. Every library that reads annotations at runtime — pydantic,
FastAPI, attrs, dataclasses with eval_str=True, your own
__annotations__ walk — breaks on that module. On 3.14, PEP 649 makes
annotations lazily evaluated, so the explosion happens on the first
get_type_hints call rather than at import: later, and further from the cause.
Two more that are real and worth knowing:
-
Connectionmust be annotated bare. typeshed gives it type parameters with defaults, so bothConnectionandConnection[Req, Resp]satisfy mypy — butConnectionis not subscriptable at runtime, so the parameterised spelling is anotherget_type_hintslandmine. Same forsharedctypes.Synchronized[int]. -
mp.Pipe()infersConnection[Any, Any], soconn.recv()is a silentAnyand everything downstream of it is unchecked.
Your task
The starter has eight functions with eight wrong annotations. Fix them so that
both gates pass — mypy --strict with zero ignores, and
typing.get_type_hints() succeeding on every one — then report where each
type really lives:
def solve(*, functions: list[str]) -> dict[str, str]:
For each named function, resolve its obj annotation with
typing.get_type_hints, normalise a generic alias to its origin with
typing.get_origin, and return __module__.
The grader asks for subsets of the eight, so there is nowhere to hide a lookup table: the answer has to come out of the annotation you wrote.
The typing lesson
This problem is the clearest example in the track of a checker being
necessary and not sufficient. mypy --strict is a static approximation of
the runtime; where the runtime object is a bound method pretending to be a
class, the approximation is simply wrong, and the only thing that finds it is
executing get_type_hints — which is what your dependencies do on import.
Add that call to a test. It costs one line and it catches an entire class of annotation bug that no checker will ever report.
Loading visualization…
Stuck?
Python reference solution
Sign in to attempt this problem and reveal the reference solution.