stubpy.diagnostics

stubpy.diagnostics

Structured warning/error accumulation for a single stub-generation pass.

Replaces the bare try/except pass blocks scattered through the pipeline with a collector that records every issue, preserving full context for debugging without silently discarding information.

Every pipeline stage is given a DiagnosticStage value so that the origin of a problem is always traceable. The DiagnosticCollector held by StubContext accumulates all diagnostics for the run; callers can inspect errors and warnings to decide how to proceed.

Usage example

from stubpy.diagnostics import DiagnosticCollector, DiagnosticLevel, DiagnosticStage

collector = DiagnosticCollector()
collector.warning(DiagnosticStage.RESOLVE, "MyClass.__init__",
                  "Could not resolve **kwargs — parent not found in MRO")

for diag in collector:
    print(diag)
# [WARNING] (resolve) MyClass.__init__: Could not resolve ...

if collector.has_errors():
    raise RuntimeError("Stub generation failed with errors")
class DiagnosticLevel(value)[source]

Bases: Enum

Severity of a single diagnostic message.

INFO = 'INFO'
WARNING = 'WARNING'
ERROR = 'ERROR'
class DiagnosticStage(value)[source]

Bases: Enum

Pipeline stage that produced a diagnostic.

Matches the stages described in the architecture document so that a diagnostic message can be traced to its origin without reading source.

LOAD = 'load'
AST_PASS = 'ast_pass'
SYMBOL_TABLE = 'symbol_table'
ALIAS = 'alias'
RESOLVE = 'resolve'
EMIT = 'emit'
IMPORT = 'import'
GENERATOR = 'generator'
class Diagnostic(level: DiagnosticLevel, stage: DiagnosticStage, symbol: str, message: str)[source]

Bases: object

An immutable record of a single issue detected during stub generation.

Parameters:
  • level (DiagnosticLevel) – Severity.

  • stage (DiagnosticStage) – Pipeline stage that raised this diagnostic.

  • symbol (str) – Human-readable name of the symbol being processed when the issue was detected (e.g. "MyClass.__init__" or "module-level").

  • message (str) – Human-readable description of the issue.

Examples

>>> from stubpy.diagnostics import Diagnostic, DiagnosticLevel, DiagnosticStage
>>> d = Diagnostic(DiagnosticLevel.WARNING, DiagnosticStage.RESOLVE,
...                "Child.__init__", "Could not resolve kwargs")
>>> str(d)
'[WARNING] (resolve) Child.__init__: Could not resolve kwargs'
level: DiagnosticLevel
stage: DiagnosticStage
symbol: str
message: str
__str__() str[source]

Return str(self).

class DiagnosticCollector(_items: list[Diagnostic] = <factory>)[source]

Bases: object

Mutable accumulator for Diagnostic records produced during one stub-generation run.

A fresh instance is created inside every StubContext and passed through the pipeline so every stage can record issues without raising exceptions.

_items

Internal ordered list. Use the public properties to access it.

Type:

list of Diagnostic

Examples

>>> collector = DiagnosticCollector()
>>> collector.warning(DiagnosticStage.EMIT, "Foo.bar", "No return annotation")
>>> collector.has_warnings()
True
>>> len(collector)
1
add(level: DiagnosticLevel, stage: DiagnosticStage, symbol: str, message: str) None[source]

Append a diagnostic record.

Parameters:
info(stage: DiagnosticStage, symbol: str, message: str) None[source]

Convenience wrapper — records an INFO diagnostic.

warning(stage: DiagnosticStage, symbol: str, message: str) None[source]

Convenience wrapper — records a WARNING diagnostic.

error(stage: DiagnosticStage, symbol: str, message: str) None[source]

Convenience wrapper — records an ERROR diagnostic.

property all: list[Diagnostic]

Return a copy of all recorded diagnostics in order.

property warnings: list[Diagnostic]

Return all WARNING diagnostics.

property errors: list[Diagnostic]

Return all ERROR diagnostics.

property infos: list[Diagnostic]

Return all INFO diagnostics.

has_errors() bool[source]

Return True if any ERROR was recorded.

has_warnings() bool[source]

Return True if any WARNING was recorded.

by_stage(stage: DiagnosticStage) list[Diagnostic][source]

Return all diagnostics from stage.

by_symbol(symbol: str) list[Diagnostic][source]

Return all diagnostics whose symbol field equals symbol.

summary() str[source]

Return a human-readable summary line.

Examples

>>> c = DiagnosticCollector()
>>> c.summary()
'0 errors, 0 warnings, 0 infos'
format_all() str[source]

Return all diagnostics joined by newlines, suitable for printing.

clear() None[source]

Remove all recorded diagnostics.

__init__(_items: list[Diagnostic] = <factory>) None

Notes

A fresh DiagnosticCollector is created inside every StubContext. Pipeline stages call info(), warning(), or error() rather than swallowing exceptions silently.

Diagnostic is a frozen dataclass(), so instances are immutable and hashable.

The --verbose CLI flag prints format_all() to stderr after the run. The --strict flag causes sys.exit(1) when has_errors() returns True.