PyArchGraph Package guides

Package 01 / pyarchgraph.domain

Domain

Understands imports and decides what the collected information means.

10 modules55 classesWalkthrough + class index

Its role

The domain gives meaning to the information collected from a Python project. It knows what a source module, import fact, dependency, and finding represent, and the rules that connect them.

Describe the source

Keep identities, import statements, context, and evidence in a shared vocabulary.

Interpret relationships

Resolve imports, build views, and explain cycles or unresolved targets.

Protect meaning

Check evidence and decide whether the declared analysis scope is complete.

The application supplies collected observations and asks these rules to work on them. The domain performs no file access and imports no graph library. Its graph contracts let an adapter supply the graph operations.

Process flow

Follow the collected sources through domain rules to the final report. The application coordinates these steps; the arrows show the main data flow, rather than parallel execution or every method call. Request and root validation happen before the observations shown here.

  • Domain rules · square corners
  • Application steps · rounded corners
  • Adapter observations · slanted sides

Scroll sideways to follow both branches of the diagram.

Domain analysis from collected sources to the final reportCollected source observations become a catalogue, resolved imports and a shared snapshot. Each registered view is built, validated and checked. A separate coverage path determines completeness. The application combines coverage and view results into the final report. View or check failures stop without a report.Sources to view resultsPer viewview reportscollection diagnosticsdiagnosticsboundariescoverage statusview failurecheck failureSources and import draftsCombine roots and pathsReconcile bindings andassign fact IDsSource catalogueReconcile targetsResolve importsSelect dependenciesBuild shared snapshotNormalise snapshotBuild and validate viewExplain cyclesRun and validate checksAssemble view reportGather coveragediagnosticsDecide completenessAssemble analysis reportExtension failure: no report
From sources to report. Scroll across the diagram on smaller screens. View editable Mermaid source.

The shared snapshot carries sources, import facts, selected dependencies, original resolver dependencies, and external or unresolved imports. Each registered view then receives its own cycle analysis and selected checks. Cycle counts are computed even when no checks are selected.

Coverage has its own rules. Collection and resolution diagnostics, layout observations, and referenced target boundaries determine completeness. The application calculates this after successful view evaluation and combines it with all view reports. A complete report can contain error findings.

Recoverable source failures continue as diagnostics alongside the available results. A registered view or check that raises or returns invalid output produces ExtensionError and stops the analysis without a report.

Which classes carry out these steps?
Flow stages and their main collaborators
StageMain classes
Collect and combineSourceCatalogBuilder coordinates SourceDiscovery and ImportFactSource, then returns SourceCatalog.
Bindings and fact IDsBindingReconciler checks cross-root bindings; FactCanonicalizer assigns stable IDs to collected drafts.
Targets and resolutionTargetReconciler combines discovered and configured declarations; StaticImportResolver interprets imports.
Dependencies and snapshotArchitectureDependencyPolicy selects relationships; AnalyseProject assembles the AnalysisSnapshot.
Normalise the snapshotSnapshotNormalizer prepares consistent shared values; GraphValidator prepares the evidence used to validate views.
Build and validate viewsGraphViewStrategy builds each view; the validation session from GraphValidator checks it.
Explain cyclesCycleAnalyzer uses GraphAlgorithms to identify cyclic groups and explain their evidence.
Run selected checksCheckStrategy produces findings; CheckResultValidator validates them. StrategyRegistry controls which checks run.
Assemble view reportsStrategyEngine combines findings and counts into each ViewReport.
Diagnostics and completenessAnalyseProject gathers diagnostics, including LayoutDiagnosticService observations. CoveragePolicy determines completeness.
Return or stopAnalyseProject assembles the AnalysisReport. View and check failures become ExtensionError instead.

Follow an import

Imagine analysing the demo directory from its parent. Both files contain an ordinary, top-level import.

The same two-file example in all three guides
# demo/orders.py
import inventory
# demo/inventory.py
import orders
  1. Give the observations stable identities

    Discovery supplies two SourceModule values. Their IDs become source:demo/orders.py and source:demo/inventory.py. Once the application has aligned paths, FactCanonicalizer turns the two drafts into identified ImportFact values.

  2. Match each import to its target

    StaticImportResolver uses known bindings to connect orders to inventory, and back again. Each DependencyEdge keeps the fact ID and resolution kind explaining why that relationship exists.

  3. Choose the relationships for analysis

    ArchitectureDependencyPolicy removes redundant package-base evidence where a fact already identifies a probable child. These plain imports keep both edges. The application places selected dependencies, the original resolver output, sources, and facts in one AnalysisSnapshot.

  4. Build a view and explain its cycle

    A view turns the snapshot into a ViewGraph. CycleAnalyzer asks the graph contract for cyclic groups, interprets the supporting facts, and selects a witness: inventory → orders → inventory.

  5. Turn the observation into a finding

    CycleCheck returns a CheckResult containing an error-level CycleFinding. The application adds the check ID and includes it in the view report.

A fact records an imported item. Resolution explains its target; evidence keeps the link back to the original statement. These are separate steps so findings stay explainable.

Views and findings

The default composition includes source and package views for each of three import filters. Source views keep one node per file; package views group those sources after filtering.

Six perspectives on the same sources
Source viewPackage viewImports retained
structuralpackage-structuralAll explicit import statements.
non-typingpackage-non-typingEverything except recognised TYPE_CHECKING bodies.
module-bodypackage-module-bodyAlso omits imports inside functions or methods; class bodies outside functions remain.

PackageView wraps a source strategy. A module belongs to its immediate containing package; an initializer belongs to its own package. Nodes use package:<dotted-name> IDs with disjoint memberships. Parent packages do not duplicate child-package sources. Standalone modules and sources without reliable bindings remain individual source nodes, so the walkthrough's two standalone files retain their cycle in all six views.

An optional max_depth caps the package's dotted name: depth 1 groups acme.orders and acme.inventory under acme; depth 2 keeps them separate. Projection drops dependencies inside a node, merges original evidence between shared endpoints and retains isolated nodes. A package cycle may exist even if no individual source modules form a cycle.

Namespace package sources group without __init__.py. An import of only the namespace container has no source target, so it does not create a graph edge. GraphValidator verifies original evidence and disjoint source memberships for package views and extensions alike.

The snapshot's optional resolved_dependencies preserves resolver evidence removed by module-level dependency selection. Package projection restores exact-base evidence only for the same retained import fact whose probable-child evidence maps to the same target package. This retains certainty without adding an unrelated package relationship. Older snapshots without the extra collection remain supported.

A cycle finding describes one cyclic group and one witness. A group can contain several cycles. “Definite” means it contains a cycle supported by exact resolution; it does not predict a crash when Python executes the project.

UnresolvedImportCheck reports unresolved imports retained by the view, except unmodelled namespace bases. Extensions may return a RuleFinding for other observations. CheckResultValidator checks their shape, source references, and evidence.

Coverage is a separate decision. CoveragePolicy requires no error diagnostics and acknowledgement of every encountered boundary. A complete analysis can still contain error findings, as this two-file example does.

Module map

Choose a module to jump to its classes below. Package initialisers are intentionally empty; callers import from the defining modules.

Where each responsibility lives
ModuleResponsibility
models.pySources, import facts, evidence, diagnostics, targets, and findings.
bindings.pyConflicting source bindings across selected roots.
canonicalization.pyStable identities and ordering for collected import facts.
targets.pyAgreement between target declarations and source package layout.
resolution.pyMatching imports to known sources and classifying other outcomes.
graph.pyThe shared analysis snapshot, view graphs, and check context.
strategies.pyBuilt-in views, cycle interpretation, and checks.
graph_algorithms.pyContracts for preparing graphs and asking cycle questions.
validation.pyConsistent snapshots, supported view evidence, and valid check results.
coverage.pyThe rules for complete analysis within the declared scope.

Every class

All 55 classes in this package, including value types, contracts, and internal helpers. Names link to the source file; descriptions match the role summaries in the code.

models.py

Sources, import facts, evidence, diagnostics, targets, and findings.

Severity
Label how seriously a diagnostic or check result should be treated.
ImportSyntax
Distinguish a plain import from a from-import statement.
ResolutionKind
Describe how an import was matched to a module, base or probable submodule.
ExternalClassification
Distinguish standard library imports from other imports outside the graph.
UnresolvedReason
Explain why an import could not be connected to an analysed source.
SourceModule
Identify a source file and record its import binding and analysis status.
ImportContext
Describe the surroundings of an import in source code for view filtering.
ImportFactDraft
Record one imported item before assigning its stable fact ID.
ImportFact
Record one imported item with its source location, context and stable ID.
Diagnostic
Record a concern about source scope, collection or resolution.
DependencyEvidence
Link a dependency to the import fact and resolution kind that support it.
DependencyEdge
Represent an import dependency between source files, with supporting facts.
ExternalImport
Record an import outside the source graph without claiming it is installed.
UnresolvedImport
Record an unmatched import, its reason and the facts that requested it.
EvidenceLocation
Locate supporting source text in a finding or target boundary.
TargetDeclaration
Describe an unanalysed target and whether its coverage limit is accepted.
TargetBoundary
Record an imported target outside analysis, with evidence and acknowledgement.
ResolutionResult
Collect resolved dependencies, other import outcomes and coverage concerns.
FindingDependency
Describe a dependency reported in a finding, with readable source evidence.
CycleFinding
Describe one cyclic group, its certainty and a representative cycle.
ImportFinding
Report a problem with an unresolved import and its supporting source evidence.
RuleFinding
Report a check's rule violation or observation about sources and view nodes.
CheckResult
Pair a finding with the severity assigned by its check.

bindings.py

Conflicting source bindings across selected roots.

BindingReconciler
Mark conflicting import bindings across selected source roots.

canonicalization.py

Stable identities and ordering for collected import facts.

FactCanonicalizer
Turn drafts into ordered import facts with stable, collision-safe IDs.

targets.py

Agreement between target declarations and source package layout.

TargetReconciler
Combine target declarations and check they fit the source package layout.

resolution.py

Matching imports to known sources and classifying other outcomes.

BindingIndex
Hold immutable source bindings, ownership and targets for one resolution.
_ResolutionSessionInternal helper
Keep results accumulated during one resolution separate from later analyses.
ImportResolver
Define how import facts are interpreted using sources and target declarations.
StaticImportResolver
Match imports using declared bindings without inspecting installed packages.
ArchitectureDependencyPolicy
Select dependencies before views, removing redundant package-base edges.

graph.py

The shared analysis snapshot, view graphs, and check context.

ViewNode
Represent one view node and the source files it groups.
ViewEvidence
Keep original source endpoints and their supporting fact visible in a view.
ViewEdge
Connect two view nodes using evidence from original source dependencies.
ViewGraph
Hold the nodes, dependencies and import fact IDs retained by one view.
AnalysisSnapshot
Provide shared source facts and the dependencies selected for module views.
CheckContext
Provide a check with one view's graph, retained imports and cycle analysis.

strategies.py

Built-in views, cycle interpretation, and checks.

GraphViewStrategy
Define how a shared analysis snapshot becomes a graph view.
CheckStrategy
Define how a view is inspected to produce findings with severity.
SourceGraphProjection
Build a view with one node per source and only the chosen import facts.
StructuralView
Include all explicit imports in a source graph view.
NonTypingView
Build a source graph view without recognised typing-only imports.
ModuleBodyView
Exclude recognised typing-only imports and those inside functions or methods.
PackageView
Group a source view by immediate package, optionally rolling up ancestors.
EvidenceInterpreter
Produce readable source evidence and remove repeated locations per dependency.
CycleAnalyzer
Interpret cycle certainty and evidence, choosing one stable witness per group.
CycleCheck
Report every analysed cycle group as an error finding.
UnresolvedImportCheck
Report unresolved imports as errors, except unmodelled namespace bases.

graph_algorithms.py

Contracts for preparing graphs and asking cycle questions.

GraphHandle
Provide reusable component and witness queries for one analysis's graph.
GraphAlgorithms
Define how cycle analysis prepares a graph without choosing a graph library.

validation.py

Consistent snapshots, supported view evidence, and valid check results.

GraphValidator
Prepare original source evidence for validating views before checks run.
_GraphValidationSessionInternal helper
Validate and order a view using one snapshot's source membership and evidence.
SnapshotNormalizer
Order and deduplicate snapshot values before they are shared with views.
CheckResultValidator
Validate immutable check results and their evidence against the analysed view.

coverage.py

The rules for complete analysis within the declared scope.

CoveragePolicy
Order diagnostics and decide whether the declared analysis scope is complete.