digitalio-stubs declares a typing.Protocol:
class DigitalInOutProtocol(Protocol):
"""Protocol for digital input/output pin control.
Any object that implements this protocol can be used as a digital pin,
providing compatibility with code expecting a `digitalio.DigitalInOut`.
"""
def deinit(self) -> None: ...
def deinited(self) -> bool: ...
...
It exists upstream so a library can accept "anything digitalio.DigitalInOut-shaped" (an I/O
expander pin, say) without importing the concrete class. The layer has no Protocol type at
all, and it is worth checking first whether PyMCU's compiler accepts typing.Protocol as a
base class before adding one here: structural typing has no run-time representation to check
against on a target with no isinstance machinery for it, so this may need compiler support,
or a decision that it type-checks under CPython only and is erased at compile time.
Found while building the CircuitPython API parity suite (tests/parity/) against
circuitpython-stubs 10.3.1: PyMCU/pymcu-circuitpython, tests/parity/allowlist.toml,
symbol digitalio.DigitalInOutProtocol.
2026-09-15: confirmed, this needs compiler support
Measured directly: from typing import Protocol alone is refused before the class body is
even reached --
error: ImportError: Module not found: typing -- 'typing' is a Python standard module, not a
PyMCU library, so `pymcu install` has nothing to fetch. PyMCU reads annotations straight
from the source, so nothing needs importing; the width names live in pymcu.types.
So this is not a matter of Protocol specifically refusing as a base class; the typing
module is not importable at all, under any stdlib flavor. There is no TYPE_CHECKING-style
guard available either, since guarding an import behind it needs the same typing import
this one already fails on. Defining DigitalInOutProtocol here needs the compiler to accept
some import from typing (even a no-op one under if TYPE_CHECKING:), which is language
work, not something this layer can route around on its own. Left tracked.
Filed as PyMCU/PyMCU#444 (milestone Types): extend the no-op handling #417 gave the guarded
try/TYPE_CHECKING forms to a bare, unguarded from typing import X.
digitalio-stubsdeclares atyping.Protocol:It exists upstream so a library can accept "anything digitalio.DigitalInOut-shaped" (an I/O
expander pin, say) without importing the concrete class. The layer has no
Protocoltype atall, and it is worth checking first whether PyMCU's compiler accepts
typing.Protocolas abase class before adding one here: structural typing has no run-time representation to check
against on a target with no
isinstancemachinery for it, so this may need compiler support,or a decision that it type-checks under CPython only and is erased at compile time.
Found while building the CircuitPython API parity suite (tests/parity/) against
circuitpython-stubs 10.3.1: PyMCU/pymcu-circuitpython, tests/parity/allowlist.toml,
symbol
digitalio.DigitalInOutProtocol.2026-09-15: confirmed, this needs compiler support
Measured directly:
from typing import Protocolalone is refused before the class body iseven reached --
So this is not a matter of
Protocolspecifically refusing as a base class; thetypingmodule is not importable at all, under any stdlib flavor. There is no
TYPE_CHECKING-styleguard available either, since guarding an import behind it needs the same
typingimportthis one already fails on. Defining
DigitalInOutProtocolhere needs the compiler to acceptsome import from
typing(even a no-op one underif TYPE_CHECKING:), which is languagework, not something this layer can route around on its own. Left tracked.
Filed as PyMCU/PyMCU#444 (milestone Types): extend the no-op handling #417 gave the guarded
try/TYPE_CHECKINGforms to a bare, unguardedfrom typing import X.