Static facts about how a module reaches its optional distributions.
Split out of :mod:symfonic.devtools.integrations.checks so the rules read
as rules: everything here answers "what does this file actually do?" from
the AST alone, and nothing here decides whether that is allowed.
carrier_modules(modules: dict[str, ModuleInfo], integration_map: IntegrationMap) -> dict[str, dict[str, bool]]
Every scanned module that reaches an optional root, with its roots.
Source code in src/symfonic/devtools/integrations/introspect.py
| def carrier_modules(
modules: dict[str, ModuleInfo], integration_map: IntegrationMap
) -> dict[str, dict[str, bool]]:
"""Every scanned module that reaches an optional root, with its roots."""
carriers: dict[str, dict[str, bool]] = {}
for name, info in modules.items():
roots = observed_roots(info, integration_map)
if roots:
carriers[name] = roots
return carriers
|
guarded_import_lines(path: Path) -> set[int]
Line numbers of imports sitting inside a try/except ImportError.
Source code in src/symfonic/devtools/integrations/introspect.py
| def guarded_import_lines(path: Path) -> set[int]:
"""Line numbers of imports sitting inside a ``try/except ImportError``."""
try:
tree = ast.parse(path.read_text(encoding="utf-8"))
except (OSError, SyntaxError): # pragma: no cover - unparsable source
return set()
lines: set[int] = set()
for node in ast.walk(tree):
if not isinstance(node, ast.Try):
continue
if not any(_catches_import_error(h) for h in node.handlers):
continue
for child in node.body:
for sub in ast.walk(child):
if isinstance(sub, (ast.Import, ast.ImportFrom)):
lines.add(sub.lineno)
return lines
|
observed_roots(info: ModuleInfo, integration_map: IntegrationMap) -> dict[str, bool]
Optional roots this module imports -> True when at module level.
Type-checking-only imports are ignored: they cost nothing at runtime,
which is the only thing the optional-dependency contract is about.
Source code in src/symfonic/devtools/integrations/introspect.py
| def observed_roots(info: ModuleInfo, integration_map: IntegrationMap) -> dict[str, bool]:
"""Optional roots this module imports -> ``True`` when at module level.
Type-checking-only imports are ignored: they cost nothing at runtime,
which is the only thing the optional-dependency contract is about.
"""
out: dict[str, bool] = {}
for record in info.imports:
if record.type_checking:
continue
root = integration_map.root_of(record.target)
if root is None:
continue
module_level = not record.lazy
out[root] = out.get(root, False) or module_level
return out
|
observed_style(info: ModuleInfo, integration_map: IntegrationMap) -> str
lazy / module-guarded / module-required for one module.
Source code in src/symfonic/devtools/integrations/introspect.py
| def observed_style(
info: ModuleInfo, integration_map: IntegrationMap
) -> str:
"""``lazy`` / ``module-guarded`` / ``module-required`` for one module."""
module_level = [
record
for record in info.imports
if not record.lazy
and not record.type_checking
and integration_map.root_of(record.target) is not None
]
if not module_level:
return "lazy"
guarded = guarded_import_lines(info.path)
if all(record.lineno in guarded for record in module_level):
return "module-guarded"
return "module-required"
|