utils/gatelock/gatelock/_xlib.py
Krzysztof kuhy Rudnicki 1723df3885 gatelock: scope pylint to source on 4.0.8 and clear the residue it grades
Same config move as crdt-sync (ignore-paths, init-hook, the three
implicit-booleaness disables the reference repos carry). The gate stays
at 8.0 for now: LockConfig's 35-field record and the two fail-open
guards in the recovery loop are still open.

Everything else pylint had left on source is gone. The optional
python-xlib dependency is loaded through one importlib helper instead
of two function-scope import statements, keeping the "not installed"
arm reachable for branch coverage; RecoveryLoop and LockWindow hold
their collaborator bundles rather than unpacking them into a second
set of attributes; the claim types are imported from _claims, where
they are defined, so _arbiter no longer needs an export list that
mirrored the package's; runtime imports sit above TYPE_CHECKING
blocks; the RandR Protocol stubs say which Xlib call they mirror.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHCbkJWXHjtTUaqvnHRAqA
2026-09-12 19:15:39 +02:00

31 lines
1.0 KiB
Python

# Copyright (c) 2026 Krzysztof Rudnicki
"""Loading the optional ``python-xlib`` dependency, in one place.
``python-xlib`` is optional: without it, output detection falls back to Tk
``<Configure>`` events plus ``xrandr`` polling. The fallback is the path that
must stay tested, and a module-scope ``try/except ImportError`` would resolve
it once at import time, leaving the ``except`` arm permanently unreachable for
branch coverage. So the modules are loaded on demand, through :mod:`importlib`,
by the two call sites that need them.
"""
from __future__ import annotations
import importlib
from types import ModuleType
def load_xlib(*names: str) -> tuple[ModuleType, ...] | None:
"""Import the named ``Xlib`` modules, or None if python-xlib is unavailable.
Args:
names: Fully-qualified module names, e.g. ``"Xlib.display"``.
Returns:
The modules in the order asked for, or None on the first ImportError.
"""
try:
return tuple(importlib.import_module(name) for name in names)
except ImportError:
return None