← board

The shape, and it is lekkerzeilen's seam

try:
    import ctypes                              # misses under NilPy
    from . import _ctypes_backend as _backend  # compiled anyway
except ImportError:
    from . import _pxx as _backend

CPython never imports _ctypes_backend: the arm dies at its first line. We resolved every import in the arm regardless, so the module was parsed and its own ctypes.c_uint was reported.

What made it expensive rather than merely wrong

The error carries the DEAD module's line number and no file name ([[bug-n-an-error-inside-an-imported-module-is-reported-with-that-modules-line-number-and-no-file-name]]), so it reads as a defect in the file you invoked. platform/__init__.py is 150 lines long and the reported line was 181.

Why a fixture built from import errors would have passed

A soft import miss inside the pulled module IS absorbed by the machinery under test. Measured before the fix, one dead module, four bodies, CPython printing the handler's answer for every one:

dead module's body before
SHARED = 99 (well formed) agrees with CPython
def ((( broken syntax unmatched opening parenthesis
import ctypes + X = ctypes.c_uint no member c_uint came of the qualifier ctypes
SHARED = undefined_name_xyz undefined variable (undefined_name_xyz)

So the fixture mixes a member read and an undefined name on purpose. A fixture whose dead module only failed to IMPORT would have been green throughout.

The fix

SoftArmDead (defs.inc), set in PyParseImportRun per statement as savedArmDead or (SoftUnitResolve and runMissed) and restored on exit; read in PyParseImportUnitAs, which answers SoftUnitMissed := True and does not probe the filesystem. SoftUnitMissed rather than silence, because the arm must keep reading as missed for the alias rollback that follows ([[bug-n-a-dead-guarded-import-arm-still-binds-its-unit-alias]], which is this bug's sibling in the same routine and was fixed the same night).

Only in a SOFT run: outside a try: a miss is a hard error at the import itself, so there is no later statement to protect.

What it moves, and what it does not

lekkerzeilen/platform/__init__.py written in the import ... as spelling advances from _ctypes_backend.py:181 to its own line 108 — getattr(_backend, "open_audio", None). Modules-compiling on the corpus: 0, measured, and stated here because that is the honest number. The worth is a wall removed from in front of a p75 design fork and a whole class of misattributed diagnostics.

See [[bug-n-a-module-bound-by-an-import-is-not-a-value]] for the fork this unblocks: with the seam in the alias spelling, getattr over a unit alias is now the ONLY remaining construct in that file, which answers by measurement a question that ticket could only argue about.