Library API¶
Prefer python -m metapathology when possible. It installs before target code
and handles target outcomes and automatic reporting. Use the API for notebooks,
embedded interpreters, or code that cannot be wrapped.
Monitor a reproduction¶
import metapathology
monitor = metapathology.install()
try:
reproduce_problem()
finally:
metapathology.write_report("diagnosis.txt")
metapathology.uninstall()
install() is process-wide. Repeating it with the same resolved capture and
analysis settings returns the existing monitor. Changing those settings while
the monitor is active raises before import state is changed.
uninstall() restores ordinary list objects and removes owned finder
instrumentation. Python cannot remove a
sys.addaudithook() hook,
so the hook remains installed but becomes inert.
For code with a clear reproduction boundary, a context manager handles cleanup:
with metapathology.monitoring() as monitor:
reproduce_problem()
metapathology.write_report("diagnosis.json", format="json")
Nested and overlapping regions share the process monitor. A context that did not create an existing installation does not remove it.
Choose what to capture¶
Defaults need no object:
Change core capture or enable all detailed capture with one object:
Use a nested object only for fine-grained detailed capture:
metapathology.CaptureConfig(
detailed=metapathology.DetailedCaptureConfig(
loaders=True,
import_results=True,
)
)
Configuration records are immutable and value-comparable. Their fields are
tri-state: True enables a mechanism, False disables it, and None means
“use the environment or normal default.” In DetailedCaptureConfig, enabled
supplies the value for detailed fields left as None.
unsafe_explore_import_branches=True calls skipped finders and hooks during the
import. Use it only in a disposable process or container. Returned specs are
discarded, but other side effects are not undone. See
Unsafe import-branch exploration.
Choose report-time checks¶
Analysis controls checks run while a report is built. Checks may call existing finder code, so they are separate from passive capture:
Pass it to install() for the default policy or override one report:
text = metapathology.render_report(
analysis=metapathology.AnalysisConfig(checks=False)
)
metapathology.write_report(
"diagnosis.json",
format="json",
analysis=metapathology.AnalysisConfig(displaced_finder_check=True),
)
A report override does not mutate the installed default.
Produce a report¶
destination=None writes to standard error. A path is replaced atomically;
streams are written directly.
render_report() returns the human-readable text report. get_report() returns
the structured ReportJSON document for programmatic inspection. JSON encoding
happens when write_report(..., format="json") writes to a destination.
Calling get_report(), render_report(), or write_report() before
installation raises RuntimeError. I/O errors from an explicit
write_report() call are re-raised. Automatic exit reporting suppresses them
so a diagnostic cannot replace the target's exit behavior.
Automatic output can be configured through install() with
report_destination, report_text, report_json, report_color, and
report_at_exit.
Inspect captured evidence¶
monitor.events() returns immutable event records copied from the monitor.
Public record names describe the observation directly, including
ImportSearchStarted, MetaPathFinderCall, ImportMechanismCall,
ImporterCacheChange, and MonitoringError.
Treat these records as low-level evidence. Integrations usually want the JSON report instead.
Monitor properties report which capture mechanisms are active and why detailed
evidence may be unavailable. In particular,
unsafe_import_branch_exploration_status is complete, partial, disabled,
or uninstalled. Partial coverage means a profiler was already installed or a
prerequisite was disabled, so some skipped calls may be missing.
Reference¶
The signatures and parameter descriptions below are generated from the library
source. Configuration fields accept True, False, or None unless stated
otherwise; None uses the corresponding environment setting or normal default.
Lifecycle¶
install
¶
install(*, report_at_exit: bool = True, report_destination: str | PathLike[str] | Sequence[str | PathLike[str]] | None = None, report_text: str | PathLike[str] | Sequence[str | PathLike[str]] | None = None, report_json: str | PathLike[str] | Sequence[str | PathLike[str]] | None = None, report_color: Literal['auto', 'always', 'never'] | None = None, report_verbosity: Literal['summary', 'standard', 'full'] | None = None, capture: CaptureConfig | None = None, analysis: AnalysisConfig | None = None, unsafe_explore_import_branches: bool | None = None) -> Monitor
Install the process-wide monitor and configure automatic reporting.
Repeating the same resolved capture and analysis configuration is idempotent. While monitoring is active, requesting a different configuration fails before import state is changed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
report_at_exit
|
bool
|
Write configured reports during normal interpreter shutdown. |
True
|
report_destination
|
str | PathLike[str] | Sequence[str | PathLike[str]] | None
|
Output path or paths whose format is inferred from
the extension. |
None
|
report_text
|
str | PathLike[str] | Sequence[str | PathLike[str]] | None
|
Path or paths forced to text format. |
None
|
report_json
|
str | PathLike[str] | Sequence[str | PathLike[str]] | None
|
Path or paths forced to JSON format. |
None
|
report_color
|
Literal['auto', 'always', 'never'] | None
|
Color policy for automatic text reports. |
None
|
report_verbosity
|
Literal['summary', 'standard', 'full'] | None
|
Text-report detail level: |
None
|
capture
|
CaptureConfig | None
|
Capture mechanisms to enable. |
None
|
analysis
|
AnalysisConfig | None
|
Report-time checks to enable. |
None
|
unsafe_explore_import_branches
|
bool | None
|
Call skipped finders and hooks during imports. This can run arbitrary foreign side effects; use it only in a disposable process. |
None
|
Returns:
| Type | Description |
|---|---|
Monitor
|
The process-wide monitor. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
An active installation uses different capture or analysis settings. |
TypeError
|
A configuration value or report destination is invalid. |
ValueError
|
A report format cannot be inferred, or a color mode or verbosity level is invalid. |
monitoring
¶
monitoring(*, capture: CaptureConfig | None = None, analysis: AnalysisConfig | None = None, unsafe_explore_import_branches: bool | None = None) -> Iterator[Monitor]
Monitor imports within a context-managed region.
Nested and overlapping regions share one process-wide monitor. If monitoring was already installed before the first region, leaving the region does not uninstall it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
capture
|
CaptureConfig | None
|
Capture mechanisms to enable. |
None
|
analysis
|
AnalysisConfig | None
|
Default report-time checks. |
None
|
unsafe_explore_import_branches
|
bool | None
|
Call skipped finders and hooks during imports. Use only in a disposable process. |
None
|
Yields:
| Type | Description |
|---|---|
Monitor
|
The process-wide monitor. |
Warns:
| Type | Description |
|---|---|
RuntimeWarning
|
Monitoring was already active before the outermost region. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
A shared active monitor uses different settings. |
uninstall
¶
Stop monitoring and restore the import state owned by metapathology.
Ordinary lists replace installed list observers and finder instrumentation is removed. The Python audit hook cannot be removed, so it remains inert. Calling this function when no monitor exists is safe.
get_monitor
¶
get_monitor() -> Monitor | None
Return the process-wide monitor if one has been created.
The returned monitor may be disabled after uninstall(). Check
monitor.enabled to distinguish that state from active monitoring.
Reports¶
write_report
¶
write_report(destination: TextIO | str | PathLike[str] | None = None, *, format: Literal['text', 'json'] = 'text', color: Literal['auto', 'always', 'never'] = 'auto', verbosity: Literal['summary', 'standard', 'full'] | None = None, analysis: AnalysisConfig | None = None) -> None
Write a report from the current capture.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
destination
|
TextIO | str | PathLike[str] | None
|
Text stream, exact output path, or |
None
|
format
|
Literal['text', 'json']
|
Output format. |
'text'
|
color
|
Literal['auto', 'always', 'never']
|
Color policy for text output. |
'auto'
|
verbosity
|
Literal['summary', 'standard', 'full'] | None
|
Text-report detail level. |
None
|
analysis
|
AnalysisConfig | None
|
Per-report analysis override. It does not change the installation default. |
None
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
Monitoring has not been installed. |
OSError
|
The destination cannot be written. |
TypeError
|
|
ValueError
|
|
get_report
¶
get_report(*, analysis: AnalysisConfig | None = None) -> ReportJSON
Return a structured report from the current capture.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
analysis
|
AnalysisConfig | None
|
Per-report analysis override. It does not change the installation default. |
None
|
Returns:
| Type | Description |
|---|---|
ReportJSON
|
A document conforming to the bundled JSON schema. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
Monitoring has not been installed. |
TypeError
|
|
render_report
¶
render_report(*, color: bool = False, verbosity: Literal['summary', 'standard', 'full'] = 'standard', analysis: AnalysisConfig | None = None) -> str
Render a human-readable report from the current capture.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
color
|
bool
|
Include terminal color escapes in the output. |
False
|
verbosity
|
Literal['summary', 'standard', 'full']
|
Text-report detail level: |
'standard'
|
analysis
|
AnalysisConfig | None
|
Per-report analysis override. It does not change the installation default. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
The complete text report. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
Monitoring has not been installed. |
TypeError
|
|
ValueError
|
|
Configuration¶
CaptureConfig
¶
Bases: _ConfigRecord
Capture settings for one installation.
Core mechanisms default to enabled. Pass detailed=True to enable every
detailed mechanism, or use DetailedCaptureConfig to select them
individually.
Attributes:
| Name | Type | Description |
|---|---|---|
import_audit |
bool | None
|
Observe import starts and direct replacement of monitored import-state lists. |
meta_path |
bool | None
|
Observe mutations to |
finder_attribution |
bool | None
|
Record calls to writable meta-path finder instances. |
path_hooks |
bool | None
|
Observe mutations to |
importer_cache |
bool | None
|
Observe changes to |
sys_path |
bool | None
|
Observe mutations to |
detailed |
bool | DetailedCaptureConfig | None
|
Detailed capture selection. |
DetailedCaptureConfig
¶
Bases: _ConfigRecord
Select individual detailed capture mechanisms.
Detailed capture adds wrappers to more of Python's import machinery and retains evidence for every observed call. Enable only the evidence needed for the reproduction.
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool | None
|
Default for any field left as |
path_hooks |
bool | None
|
Record calls to |
path_entry_finders |
bool | None
|
Record calls to path-entry finders. |
loaders |
bool | None
|
Record loader execution calls. |
import_results |
bool | None
|
Match import attempts to exact outcomes where possible. |
import_calls |
bool | None
|
Record calls through |
AnalysisConfig
¶
Bases: _ConfigRecord
Choose current-state checks performed while building a report.
These checks may call finder code at report time. They do not affect the monitored import outcomes.
Attributes:
| Name | Type | Description |
|---|---|---|
checks |
bool | None
|
Default for check fields left as |
standard_path_check |
bool | None
|
Compare captured custom-finder results with a
current-state |
displaced_finder_check |
bool | None
|
Call finders that are no longer in their captured position. Disabled by default. |
Monitor
¶
Captured import-machinery evidence for the current process.
Obtain this object from install() or monitoring(); constructing it
directly does not start monitoring. Event accessors return snapshots, so
callers cannot mutate the monitor's internal evidence.
import_audit_enabled
property
¶
import_audit_enabled: bool
Whether import audit starts and reassignment recovery are active.
meta_path_enabled
property
¶
meta_path_enabled: bool
Whether reversible sys.meta_path list observation is active.
finder_attribution_enabled
property
¶
finder_attribution_enabled: bool
Whether writable finder instances are shadowed for attribution.
path_hooks_enabled
property
¶
path_hooks_enabled: bool
Whether sys.path_hooks mutation monitoring is currently active.
importer_cache_enabled
property
¶
importer_cache_enabled: bool
Whether passive sys.path_importer_cache monitoring is active.
sys_path_enabled
property
¶
sys_path_enabled: bool
Whether opt-in sys.path mutation monitoring is active.
detailed_capture
property
¶
Names of active detailed capture mechanisms.
import_results_capture_status
property
¶
Activation state and thread scope of exact import outcomes.
import_calls_capture_status
property
¶
Activation state of builtins.__import__ call observation.
path_finder_capture_status
property
¶
Availability of exact aggregate standard-finder evidence.
unsafe_import_branch_exploration_status
property
¶
unsafe_import_branch_exploration_status: str
Coverage of unsafe branch exploration.
The value is "complete", "partial", "disabled", or
"uninstalled". Partial coverage means prerequisite capture was
disabled or an existing profiler prevented some calls from being
observed.
events
¶
Return a snapshot of all recorded events in capture order.
The list is independent of the monitor. Its event records are immutable.