modwire 9.0.0__tar.gz → 9.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modwire-9.0.0 → modwire-9.2.0}/.dev/modwire.egg-info/SOURCES.txt +19 -0
- {modwire-9.0.0 → modwire-9.2.0}/Makefile +4 -1
- {modwire-9.0.0 → modwire-9.2.0}/PKG-INFO +53 -1
- {modwire-9.0.0 → modwire-9.2.0}/README.md +52 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/application.py +78 -2
- modwire-9.2.0/src/modwire/cli/cache/application.py +230 -0
- modwire-9.2.0/src/modwire/cli/cache/domain.py +27 -0
- modwire-9.2.0/src/modwire/cli/cache/models/cache_entry.py +8 -0
- modwire-9.2.0/src/modwire/cli/cache/models/cache_key.py +11 -0
- modwire-9.2.0/src/modwire/cli/cache/models/cache_options.py +25 -0
- modwire-9.2.0/src/modwire/cli/cache/models/cache_outcome.py +44 -0
- modwire-9.2.0/src/modwire/cli/cache/models/cached_result.py +29 -0
- modwire-9.2.0/src/modwire/cli/cache/models/extraction_snapshot.py +8 -0
- modwire-9.2.0/src/modwire/cli/cache/models/source_entry.py +9 -0
- modwire-9.2.0/src/modwire/cli/cache/models/source_inventory.py +9 -0
- modwire-9.2.0/src/modwire/cli/cache/services/cache_codec.py +40 -0
- modwire-9.2.0/src/modwire/cli/cache/services/cache_identity.py +106 -0
- modwire-9.2.0/src/modwire/cli/cache/services/filesystem_cache_storage.py +147 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/facade.py +60 -6
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/domain.py +13 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/command_request.py +5 -1
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/batch_source_reader.py +57 -15
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/command_line.py +11 -1
- modwire-9.2.0/tests/application/test_07_cache.py +230 -0
- modwire-9.2.0/tests/extraction/cache_benchmark/run.py +155 -0
- modwire-9.2.0/tests/extraction/scan_benchmark/__init__.py +0 -0
- modwire-9.2.0/tests/shared/__init__.py +0 -0
- modwire-9.2.0/tests/shared/code/__init__.py +0 -0
- modwire-9.2.0/tests/support/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/.github/workflows/ci.yml +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/.github/workflows/release.yml +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/.gitignore +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/AGENTS.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/LICENSE +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/MANIFEST.in +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/docs/target-language-ownership.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/pyproject.toml +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/scripts/check_extractors.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/scripts/generate_docs.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/scripts/verify_consumer.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/setup.cfg +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/setup.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/__main__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/edge_rule_violation.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/flow_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/flow_violation.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/types.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/backward_flow_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/boundaries_flow_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/module_boundary_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/no_cycles_flow_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/no_reentry_flow_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/architecture_config.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/boundaries_config.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/boundary_rule.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/configuration_value.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/flow_realm.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/flow_rules.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/shape_config.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/shape_realm.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/shape_rules.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/tag_rule.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/facade.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/callable_report_entry.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/callables_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/clusters_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/clusters_report_item.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/coherence_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/exports_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/exports_report_item.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/hotspots_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/hotspots_report_item.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/insight_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/callables_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/clusters_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/coherence_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/exports_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/hotspots_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/insight_report_field_map.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/architecture_map.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/architecture_realm.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/tag_map.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/tag_match.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/services/architecture_map_loader.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/services/tag_matcher.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/architecture_group.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/map_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_catalog.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_descriptor.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_item.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_metadata.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_node.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_section.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/services/map_report_collector.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/models/shape_realm_architecture_map.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/models/shape_report.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/models/shape_violation.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/abstract_class_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/callable_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/class_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/file_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/import_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/property_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/signature_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/symbol_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/autowiring.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/__init__.py +0 -0
- {modwire-9.0.0/src/modwire/cli/resources/models → modwire-9.2.0/src/modwire/cli/cache}/__init__.py +0 -0
- {modwire-9.0.0/src/modwire/extraction → modwire-9.2.0/src/modwire/cli/cache/models}/__init__.py +0 -0
- {modwire-9.0.0/src/modwire/shared → modwire-9.2.0/src/modwire/cli/cache/services}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/documentation/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/documentation/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/documentation/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/documentation/services/documentation_generator.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/models/initialization_result.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/services/initialization_service.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/extractor_batch_input.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/extractor_command_input.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/extractor_source_input.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/report_pipeline_context.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/scan_policy.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/callables_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/clusters_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/coherence_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/configuration_loader.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/extractor_command.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/flow_violations.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/hotspots_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/map_tree.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/output_console.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/shape_violations.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/success.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/unknown_files_warning.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/unused_exports_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/application.py +0 -0
- {modwire-9.0.0/src/modwire/shared/values → modwire-9.2.0/src/modwire/cli/resources}/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/models/defaults.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/models/init_asset.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/AGENTS.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/ARCHITECTURE.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/INDEX.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/MODWIRE.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/RULES.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/TESTING.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/WORKFLOW.md +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/architecture.yaml +0 -0
- {modwire-9.0.0/tests → modwire-9.2.0/src/modwire/extraction}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/services/graph_builder.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/services/import_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/services/suffix_index.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/batch_config.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/extraction_request.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/extractor_resource.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/extractor_runtime.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/python_call_context.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/build.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/build.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/composer.json +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/composer.lock +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/script.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/script.src.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/python/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/python/script.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/build.mjs +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/build.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/package-lock.json +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/package.json +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/script.js +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/script.ts +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/tsconfig.json +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/php_extractor.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/python_call_reader.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/python_extractor.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/python_syntax_parser.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/type_script_extractor.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/facade.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/py.typed +0 -0
- {modwire-9.0.0/tests/application → modwire-9.2.0/src/modwire/shared}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/application.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/code_map.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/code_package.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/dependency_edge_result.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/dependency_graph.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/dependency_node_result.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/duplicate_identity_error.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/edge.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/edge_resolution.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/identity.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/node.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/query_builder.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/query_types.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/queryable_code_map.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_abstract_class.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_call.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_callable.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_callable_symbol.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_class.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_class_method.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_class_property.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_export.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_extraction.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_file.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_file_result.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_function.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_import.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_imported_symbol.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_interface.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_item_result.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_parameter.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_signature.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_symbol.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_type.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_value.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/types.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/services/glob_path_matcher.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/services/identity_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/values/__init__.py +0 -0
- {modwire-9.0.0/tests/architecture → modwire-9.2.0/src/modwire/shared/values/models}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/values/models/value_model.py +0 -0
- {modwire-9.0.0/tests/architecture/boundaries → modwire-9.2.0/tests}/__init__.py +0 -0
- {modwire-9.0.0/tests/architecture/config → modwire-9.2.0/tests/application}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/application/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/application/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/application/test_06_happy_path.py +0 -0
- {modwire-9.0.0/tests/architecture/insights → modwire-9.2.0/tests/architecture}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/base_test.py +0 -0
- {modwire-9.0.0/tests/architecture/map → modwire-9.2.0/tests/architecture/boundaries}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/test_03_public_api.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/test_04_paths.py +0 -0
- {modwire-9.0.0/tests/architecture/report → modwire-9.2.0/tests/architecture/config}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/config/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/config/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/architecture/shape → modwire-9.2.0/tests/architecture/insights}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/insights/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/insights/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/cli → modwire-9.2.0/tests/architecture/map}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/map/test_02_patterns.py +0 -0
- {modwire-9.0.0/tests/cli/documentation → modwire-9.2.0/tests/architecture/report}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/report/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/cli/initialization → modwire-9.2.0/tests/architecture/shape}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/shape/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/shape/test_01_limits.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/shape/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/cli/pipeline → modwire-9.2.0/tests/cli}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/base_test.py +0 -0
- {modwire-9.0.0/tests/extraction → modwire-9.2.0/tests/cli/documentation}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/documentation/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/extraction/big_projects → modwire-9.2.0/tests/cli/initialization}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_03_interruption.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_04_cleanup.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_05_recovery.py +0 -0
- {modwire-9.0.0/tests/extraction/dependency → modwire-9.2.0/tests/cli/pipeline}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_03_interruption.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_04_command_transport.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_05_recovery.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_06_happy_path.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/conftest.py +0 -0
- {modwire-9.0.0/tests/extraction/extractors → modwire-9.2.0/tests/extraction}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/base_test.py +0 -0
- {modwire-9.0.0/tests/extraction/scan_benchmark → modwire-9.2.0/tests/extraction/big_projects}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/project.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/projects.json +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/resolution_results.json +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/results.json +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/run.py +0 -0
- {modwire-9.0.0/tests/shared → modwire-9.2.0/tests/extraction/cache_benchmark}/__init__.py +0 -0
- {modwire-9.0.0/tests/shared/code → modwire-9.2.0/tests/extraction/dependency}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/dependency/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/support → modwire-9.2.0/tests/extraction/extractors}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/extractors/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/extractors/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/extractors/test_03_native_symbols.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/scan_benchmark/prepare.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/scan_benchmark/results.json +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/scan_benchmark/run.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/ignored/example_generated.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/src/example_application/example_actions/example_action.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/src/example_domain/example_model/example_record.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/src/example_domain/example_services/example_policy.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/src/example_interfaces/example_http/example_controller.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/ignored/example_generated.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/src/example_application/example_actions/example_action.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/src/example_domain/example_model/example_record.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/src/example_domain/example_services/example_policy.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/src/example_interfaces/example_http/example_controller.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/ignored/example_generated.ts +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_application/example_actions/example_action.ts +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_record.ts +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_view.tsx +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_audit.js +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_callables.ts +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_policy.ts +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_controller.ts +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_view.jsx +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/syntax/php/example_shapes.php +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/syntax/python/example_shapes.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/syntax/typescript/example_shapes.ts +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/shared/code/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/support/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/support/code_map.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/tests/support/service_test.py +0 -0
- {modwire-9.0.0 → modwire-9.2.0}/uv.lock +0 -0
|
@@ -112,6 +112,22 @@ src/modwire/architecture/shape/services/signature_resolver.py
|
|
|
112
112
|
src/modwire/architecture/shape/services/symbol_resolver.py
|
|
113
113
|
src/modwire/cli/__init__.py
|
|
114
114
|
src/modwire/cli/facade.py
|
|
115
|
+
src/modwire/cli/cache/__init__.py
|
|
116
|
+
src/modwire/cli/cache/application.py
|
|
117
|
+
src/modwire/cli/cache/domain.py
|
|
118
|
+
src/modwire/cli/cache/models/__init__.py
|
|
119
|
+
src/modwire/cli/cache/models/cache_entry.py
|
|
120
|
+
src/modwire/cli/cache/models/cache_key.py
|
|
121
|
+
src/modwire/cli/cache/models/cache_options.py
|
|
122
|
+
src/modwire/cli/cache/models/cache_outcome.py
|
|
123
|
+
src/modwire/cli/cache/models/cached_result.py
|
|
124
|
+
src/modwire/cli/cache/models/extraction_snapshot.py
|
|
125
|
+
src/modwire/cli/cache/models/source_entry.py
|
|
126
|
+
src/modwire/cli/cache/models/source_inventory.py
|
|
127
|
+
src/modwire/cli/cache/services/__init__.py
|
|
128
|
+
src/modwire/cli/cache/services/cache_codec.py
|
|
129
|
+
src/modwire/cli/cache/services/cache_identity.py
|
|
130
|
+
src/modwire/cli/cache/services/filesystem_cache_storage.py
|
|
115
131
|
src/modwire/cli/documentation/__init__.py
|
|
116
132
|
src/modwire/cli/documentation/application.py
|
|
117
133
|
src/modwire/cli/documentation/services/__init__.py
|
|
@@ -253,6 +269,7 @@ tests/application/__init__.py
|
|
|
253
269
|
tests/application/base_test.py
|
|
254
270
|
tests/application/test_01_attacks.py
|
|
255
271
|
tests/application/test_06_happy_path.py
|
|
272
|
+
tests/application/test_07_cache.py
|
|
256
273
|
tests/architecture/__init__.py
|
|
257
274
|
tests/architecture/base_test.py
|
|
258
275
|
tests/architecture/boundaries/__init__.py
|
|
@@ -301,6 +318,8 @@ tests/extraction/big_projects/projects.json
|
|
|
301
318
|
tests/extraction/big_projects/resolution_results.json
|
|
302
319
|
tests/extraction/big_projects/results.json
|
|
303
320
|
tests/extraction/big_projects/run.py
|
|
321
|
+
tests/extraction/cache_benchmark/__init__.py
|
|
322
|
+
tests/extraction/cache_benchmark/run.py
|
|
304
323
|
tests/extraction/dependency/__init__.py
|
|
305
324
|
tests/extraction/dependency/test_02_invariants.py
|
|
306
325
|
tests/extraction/extractors/__init__.py
|
|
@@ -7,7 +7,7 @@ PROJECT_ROOT := $(CURDIR)
|
|
|
7
7
|
export PYTHONPYCACHEPREFIX := $(PROJECT_ROOT)/$(DEV_DIR)/cache/python
|
|
8
8
|
export UV_CACHE_DIR := $(PROJECT_ROOT)/$(DEV_DIR)/cache/uv
|
|
9
9
|
|
|
10
|
-
.PHONY: big-projects build ci docs docs-check extractor-check format format-check host-check lint package-check scan-benchmark scan-benchmark-fixture test type-check
|
|
10
|
+
.PHONY: big-projects build cache-benchmark ci docs docs-check extractor-check format format-check host-check lint package-check scan-benchmark scan-benchmark-fixture test type-check
|
|
11
11
|
|
|
12
12
|
format:
|
|
13
13
|
uv run ruff format src tests scripts
|
|
@@ -34,6 +34,9 @@ scan-benchmark-fixture:
|
|
|
34
34
|
scan-benchmark:
|
|
35
35
|
uv run python -m tests.extraction.scan_benchmark.run --root .dev/benchmarks/scan-project --language "$(SCAN_BENCHMARK_LANGUAGE)" --excluded-pattern 'example_excluded/**'
|
|
36
36
|
|
|
37
|
+
cache-benchmark:
|
|
38
|
+
uv run python -m tests.extraction.cache_benchmark.run --root "$(CACHE_BENCHMARK_ROOT)" --language "$(CACHE_BENCHMARK_LANGUAGE)" --cache-directory .dev/benchmarks/cache --incremental-source "$(CACHE_BENCHMARK_SOURCE)" --replacement-source "$(CACHE_BENCHMARK_REPLACEMENT)"
|
|
39
|
+
|
|
37
40
|
docs-check:
|
|
38
41
|
uv run python scripts/generate_docs.py --check
|
|
39
42
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modwire
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.2.0
|
|
4
4
|
Summary: Code extraction, architecture analysis and the Modwire CLI.
|
|
5
5
|
Author: Tomasz Szpak
|
|
6
6
|
License-Expression: MIT
|
|
@@ -48,6 +48,14 @@ Return the available architecture reports.
|
|
|
48
48
|
|
|
49
49
|
Analyze a code map with a validated architecture configuration.
|
|
50
50
|
|
|
51
|
+
### `analyze_cached`
|
|
52
|
+
|
|
53
|
+
Analyze a code map, reusing reports for an exact map and configuration identity.
|
|
54
|
+
|
|
55
|
+
### `analyze_cached_with_diagnostics`
|
|
56
|
+
|
|
57
|
+
Analyze a code map and report the public outcome of report-cache reuse.
|
|
58
|
+
|
|
51
59
|
### `discover`
|
|
52
60
|
|
|
53
61
|
Discover supported source languages beneath a root using the caller's scan policy.
|
|
@@ -64,6 +72,26 @@ descendants are deliberately unobserved and are not included in file counts.
|
|
|
64
72
|
|
|
65
73
|
Extract source files and return a queryable code map.
|
|
66
74
|
|
|
75
|
+
### `generate_map_cached`
|
|
76
|
+
|
|
77
|
+
Return a code map with content-addressed source and complete-manifest reuse.
|
|
78
|
+
|
|
79
|
+
### `generate_map_cached_with_diagnostics`
|
|
80
|
+
|
|
81
|
+
Return a code map and public outcomes for extraction and complete-map reuse.
|
|
82
|
+
|
|
83
|
+
### `generate_queryable_map_cached`
|
|
84
|
+
|
|
85
|
+
Return a queryable code map with content-addressed persistent reuse.
|
|
86
|
+
|
|
87
|
+
### `generate_queryable_map_cached_with_diagnostics`
|
|
88
|
+
|
|
89
|
+
Return a queryable code map and public outcomes for every applicable cache stage.
|
|
90
|
+
|
|
91
|
+
### `clear_cache`
|
|
92
|
+
|
|
93
|
+
Clear only the Modwire-owned directory for one cache namespace.
|
|
94
|
+
|
|
67
95
|
### `load_configuration`
|
|
68
96
|
|
|
69
97
|
Load and validate an architecture configuration from a directory.
|
|
@@ -84,6 +112,30 @@ Run the native extractor transport for one supported language.
|
|
|
84
112
|
|
|
85
113
|
Run the Modwire command line interface and return its process status.
|
|
86
114
|
|
|
115
|
+
## `CacheStage`
|
|
116
|
+
|
|
117
|
+
Public stages reported by cached Modwire operations.
|
|
118
|
+
|
|
119
|
+
## `CacheOutcome`
|
|
120
|
+
|
|
121
|
+
Content-safe lifecycle counts for one stage of a cached operation.
|
|
122
|
+
|
|
123
|
+
Extraction counts describe current source records. Code-map and report counts
|
|
124
|
+
describe one entry. Invalidated entries are also misses. Diagnostics include
|
|
125
|
+
the configured namespace but never cache keys, source identities, or content.
|
|
126
|
+
|
|
127
|
+
## `CachedResult`
|
|
128
|
+
|
|
129
|
+
A cached operation value together with one outcome per applicable stage.
|
|
130
|
+
|
|
131
|
+
### `outcome`
|
|
132
|
+
|
|
133
|
+
Return the outcome for one applicable cache stage.
|
|
134
|
+
|
|
135
|
+
## `CacheOptions`
|
|
136
|
+
|
|
137
|
+
Generic persistent-cache settings supplied by a caller.
|
|
138
|
+
|
|
87
139
|
## `ScanPolicy`
|
|
88
140
|
|
|
89
141
|
Caller-owned filesystem traversal policy with explicit exclusions and opt-in symlink following.
|
|
@@ -20,6 +20,14 @@ Return the available architecture reports.
|
|
|
20
20
|
|
|
21
21
|
Analyze a code map with a validated architecture configuration.
|
|
22
22
|
|
|
23
|
+
### `analyze_cached`
|
|
24
|
+
|
|
25
|
+
Analyze a code map, reusing reports for an exact map and configuration identity.
|
|
26
|
+
|
|
27
|
+
### `analyze_cached_with_diagnostics`
|
|
28
|
+
|
|
29
|
+
Analyze a code map and report the public outcome of report-cache reuse.
|
|
30
|
+
|
|
23
31
|
### `discover`
|
|
24
32
|
|
|
25
33
|
Discover supported source languages beneath a root using the caller's scan policy.
|
|
@@ -36,6 +44,26 @@ descendants are deliberately unobserved and are not included in file counts.
|
|
|
36
44
|
|
|
37
45
|
Extract source files and return a queryable code map.
|
|
38
46
|
|
|
47
|
+
### `generate_map_cached`
|
|
48
|
+
|
|
49
|
+
Return a code map with content-addressed source and complete-manifest reuse.
|
|
50
|
+
|
|
51
|
+
### `generate_map_cached_with_diagnostics`
|
|
52
|
+
|
|
53
|
+
Return a code map and public outcomes for extraction and complete-map reuse.
|
|
54
|
+
|
|
55
|
+
### `generate_queryable_map_cached`
|
|
56
|
+
|
|
57
|
+
Return a queryable code map with content-addressed persistent reuse.
|
|
58
|
+
|
|
59
|
+
### `generate_queryable_map_cached_with_diagnostics`
|
|
60
|
+
|
|
61
|
+
Return a queryable code map and public outcomes for every applicable cache stage.
|
|
62
|
+
|
|
63
|
+
### `clear_cache`
|
|
64
|
+
|
|
65
|
+
Clear only the Modwire-owned directory for one cache namespace.
|
|
66
|
+
|
|
39
67
|
### `load_configuration`
|
|
40
68
|
|
|
41
69
|
Load and validate an architecture configuration from a directory.
|
|
@@ -56,6 +84,30 @@ Run the native extractor transport for one supported language.
|
|
|
56
84
|
|
|
57
85
|
Run the Modwire command line interface and return its process status.
|
|
58
86
|
|
|
87
|
+
## `CacheStage`
|
|
88
|
+
|
|
89
|
+
Public stages reported by cached Modwire operations.
|
|
90
|
+
|
|
91
|
+
## `CacheOutcome`
|
|
92
|
+
|
|
93
|
+
Content-safe lifecycle counts for one stage of a cached operation.
|
|
94
|
+
|
|
95
|
+
Extraction counts describe current source records. Code-map and report counts
|
|
96
|
+
describe one entry. Invalidated entries are also misses. Diagnostics include
|
|
97
|
+
the configured namespace but never cache keys, source identities, or content.
|
|
98
|
+
|
|
99
|
+
## `CachedResult`
|
|
100
|
+
|
|
101
|
+
A cached operation value together with one outcome per applicable stage.
|
|
102
|
+
|
|
103
|
+
### `outcome`
|
|
104
|
+
|
|
105
|
+
Return the outcome for one applicable cache stage.
|
|
106
|
+
|
|
107
|
+
## `CacheOptions`
|
|
108
|
+
|
|
109
|
+
Generic persistent-cache settings supplied by a caller.
|
|
110
|
+
|
|
59
111
|
## `ScanPolicy`
|
|
60
112
|
|
|
61
113
|
Caller-owned filesystem traversal policy with explicit exclusions and opt-in symlink following.
|
|
@@ -10,13 +10,25 @@ from .architecture.config.models.architecture_config import ArchitectureConfig
|
|
|
10
10
|
from .architecture.facade import ArchitectureFacade
|
|
11
11
|
from .architecture.report.models.report_catalog import ReportCatalog
|
|
12
12
|
from .architecture.report.models.report_node import ReportNode
|
|
13
|
+
from .cli.cache.models.cache_options import CacheOptions
|
|
14
|
+
from .cli.cache.models.cache_outcome import CacheOutcome, CacheStage
|
|
15
|
+
from .cli.cache.models.cached_result import CachedResult
|
|
13
16
|
from .cli.facade import CliFacade
|
|
14
17
|
from .cli.pipeline.models.scan_policy import ScanPolicy
|
|
15
18
|
from .extraction.facade import ExtractionFacade
|
|
16
19
|
from .shared.code.models.code_map import CodeMap
|
|
17
20
|
from .shared.code.models.queryable_code_map import QueryableCodeMap
|
|
18
21
|
|
|
19
|
-
__all__ = [
|
|
22
|
+
__all__ = [
|
|
23
|
+
"CacheOptions",
|
|
24
|
+
"CacheOutcome",
|
|
25
|
+
"CacheStage",
|
|
26
|
+
"CachedResult",
|
|
27
|
+
"CodeMap",
|
|
28
|
+
"ModwireApplication",
|
|
29
|
+
"QueryableCodeMap",
|
|
30
|
+
"ScanPolicy",
|
|
31
|
+
]
|
|
20
32
|
|
|
21
33
|
|
|
22
34
|
@dataclass(frozen=True)
|
|
@@ -56,6 +68,26 @@ class ModwireApplication:
|
|
|
56
68
|
|
|
57
69
|
return self.architecture.analyze(code_map, config)
|
|
58
70
|
|
|
71
|
+
def analyze_cached(
|
|
72
|
+
self, code_map: QueryableCodeMap, config: ArchitectureConfig, options: CacheOptions
|
|
73
|
+
) -> tuple[ReportNode, ...]:
|
|
74
|
+
"""Analyze a code map, reusing reports for an exact map and configuration identity."""
|
|
75
|
+
|
|
76
|
+
return self.analyze_cached_with_diagnostics(code_map, config, options).value
|
|
77
|
+
|
|
78
|
+
def analyze_cached_with_diagnostics(
|
|
79
|
+
self, code_map: QueryableCodeMap, config: ArchitectureConfig, options: CacheOptions
|
|
80
|
+
) -> CachedResult[tuple[ReportNode, ...]]:
|
|
81
|
+
"""Analyze a code map and report the public outcome of report-cache reuse."""
|
|
82
|
+
|
|
83
|
+
cached = self.cli.cached_reports(code_map.code_map, config, options)
|
|
84
|
+
if cached.value is not None:
|
|
85
|
+
return CachedResult(value=cached.value, outcomes=cached.outcomes)
|
|
86
|
+
reports = self.architecture.analyze(code_map, config)
|
|
87
|
+
self.cli.store_reports(code_map.code_map, config, reports, options)
|
|
88
|
+
outcome = cached.outcome(CacheStage.REPORTS).model_copy(update={"computed": 1, "stored": 1})
|
|
89
|
+
return CachedResult(value=reports, outcomes=(outcome,))
|
|
90
|
+
|
|
59
91
|
def discover(self, root: str, policy: ScanPolicy) -> tuple[str, ...]:
|
|
60
92
|
"""Discover supported source languages beneath a root using the caller's scan policy."""
|
|
61
93
|
|
|
@@ -81,6 +113,48 @@ class ModwireApplication:
|
|
|
81
113
|
|
|
82
114
|
return QueryableCodeMap(code_map=self.generate_map(language, root, policy))
|
|
83
115
|
|
|
116
|
+
def generate_map_cached(self, language: str, root: str, policy: ScanPolicy, options: CacheOptions) -> CodeMap:
|
|
117
|
+
"""Return a code map with content-addressed source and complete-manifest reuse."""
|
|
118
|
+
|
|
119
|
+
return self.generate_map_cached_with_diagnostics(language, root, policy, options).value
|
|
120
|
+
|
|
121
|
+
def generate_map_cached_with_diagnostics(
|
|
122
|
+
self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
|
|
123
|
+
) -> CachedResult[CodeMap]:
|
|
124
|
+
"""Return a code map and public outcomes for extraction and complete-map reuse."""
|
|
125
|
+
|
|
126
|
+
request = self.extraction.request(language, str(root))
|
|
127
|
+
snapshot = self.cli.extract_cached(request, policy, options)
|
|
128
|
+
cached = self.cli.cached_code_map(snapshot.value, options)
|
|
129
|
+
outcome = cached.outcome(CacheStage.CODE_MAP)
|
|
130
|
+
if cached.value is not None:
|
|
131
|
+
code_map = cached.value
|
|
132
|
+
else:
|
|
133
|
+
code_map = self.extraction.generate_map(language, snapshot.value.extraction)
|
|
134
|
+
self.cli.store_code_map(snapshot.value, code_map, options)
|
|
135
|
+
outcome = outcome.model_copy(update={"computed": 1, "stored": 1})
|
|
136
|
+
return CachedResult(value=code_map, outcomes=(*snapshot.outcomes, outcome))
|
|
137
|
+
|
|
138
|
+
def generate_queryable_map_cached(
|
|
139
|
+
self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
|
|
140
|
+
) -> QueryableCodeMap:
|
|
141
|
+
"""Return a queryable code map with content-addressed persistent reuse."""
|
|
142
|
+
|
|
143
|
+
return self.generate_queryable_map_cached_with_diagnostics(language, root, policy, options).value
|
|
144
|
+
|
|
145
|
+
def generate_queryable_map_cached_with_diagnostics(
|
|
146
|
+
self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
|
|
147
|
+
) -> CachedResult[QueryableCodeMap]:
|
|
148
|
+
"""Return a queryable code map and public outcomes for every applicable cache stage."""
|
|
149
|
+
|
|
150
|
+
cached = self.generate_map_cached_with_diagnostics(language, root, policy, options)
|
|
151
|
+
return CachedResult(value=QueryableCodeMap(code_map=cached.value), outcomes=cached.outcomes)
|
|
152
|
+
|
|
153
|
+
def clear_cache(self, options: CacheOptions) -> None:
|
|
154
|
+
"""Clear only the Modwire-owned directory for one cache namespace."""
|
|
155
|
+
|
|
156
|
+
self.cli.clear_cache(options)
|
|
157
|
+
|
|
84
158
|
def load_configuration(self, dot_dir: str) -> ArchitectureConfig:
|
|
85
159
|
"""Load and validate an architecture configuration from a directory."""
|
|
86
160
|
|
|
@@ -94,7 +168,9 @@ class ModwireApplication:
|
|
|
94
168
|
def generate_documentation(self, readme: str, check: bool) -> int:
|
|
95
169
|
"""Generate this README from the published interface docstrings, or check that it is current."""
|
|
96
170
|
|
|
97
|
-
return self.cli.generate_documentation(
|
|
171
|
+
return self.cli.generate_documentation(
|
|
172
|
+
str(readme), (type(self), CacheStage, CacheOutcome, CachedResult, CacheOptions, ScanPolicy), check
|
|
173
|
+
)
|
|
98
174
|
|
|
99
175
|
def run_extractor(self, language: str) -> int:
|
|
100
176
|
"""Run the native extractor transport for one supported language."""
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any, cast
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ValidationError
|
|
6
|
+
from wireup import injectable
|
|
7
|
+
|
|
8
|
+
from ...architecture.config.models.architecture_config import ArchitectureConfig
|
|
9
|
+
from ...architecture.report.models.report_node import ReportNode
|
|
10
|
+
from ...extraction.extractors.models.extraction_request import ExtractionRequest
|
|
11
|
+
from ...shared.code.models.code_map import CodeMap
|
|
12
|
+
from ...shared.code.models.duplicate_identity_error import DuplicateIdentityError
|
|
13
|
+
from ...shared.code.models.identity import FileId, ModuleId
|
|
14
|
+
from ...shared.code.models.source_extraction import SourceExtraction
|
|
15
|
+
from ...shared.code.models.source_file import SourceFile
|
|
16
|
+
from ..pipeline.domain import SourceReader
|
|
17
|
+
from ..pipeline.models.scan_policy import ScanPolicy
|
|
18
|
+
from .domain import CacheStorage
|
|
19
|
+
from .models.cache_key import CacheKey
|
|
20
|
+
from .models.cache_options import CacheOptions
|
|
21
|
+
from .models.cache_outcome import CacheOutcome, CacheStage
|
|
22
|
+
from .models.cached_result import CachedResult
|
|
23
|
+
from .models.extraction_snapshot import ExtractionSnapshot
|
|
24
|
+
from .services.cache_codec import CacheCodec
|
|
25
|
+
from .services.cache_identity import CacheIdentity
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class _CacheRead:
|
|
30
|
+
value: object | None
|
|
31
|
+
invalidated: bool
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@injectable
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class CacheApplication:
|
|
37
|
+
reader: SourceReader
|
|
38
|
+
storage: CacheStorage
|
|
39
|
+
identity: CacheIdentity
|
|
40
|
+
codec: CacheCodec
|
|
41
|
+
|
|
42
|
+
def has_source_files(self, request: ExtractionRequest, policy: ScanPolicy) -> bool:
|
|
43
|
+
return self.reader.has_source_files(request, policy)
|
|
44
|
+
|
|
45
|
+
def extract(self, request: ExtractionRequest, policy: ScanPolicy) -> SourceExtraction:
|
|
46
|
+
self.reader.ensure_available(request.runtime)
|
|
47
|
+
return self.reader.extract_source(request, policy)
|
|
48
|
+
|
|
49
|
+
def extract_cached(
|
|
50
|
+
self, request: ExtractionRequest, policy: ScanPolicy, options: CacheOptions
|
|
51
|
+
) -> CachedResult[ExtractionSnapshot]:
|
|
52
|
+
inventory = self.reader.inventory(request, policy)
|
|
53
|
+
keys = {entry.source_id: self.identity.source(request, policy, entry) for entry in inventory.entries}
|
|
54
|
+
files: dict[FileId, SourceFile] = {}
|
|
55
|
+
misses: list[FileId] = []
|
|
56
|
+
hits = 0
|
|
57
|
+
invalidated = 0
|
|
58
|
+
for entry in inventory.entries:
|
|
59
|
+
key = keys[entry.source_id]
|
|
60
|
+
cached = self._read(options, key)
|
|
61
|
+
try:
|
|
62
|
+
source_file = SourceFile.model_validate(cached.value)
|
|
63
|
+
if source_file.file_id != entry.source_id:
|
|
64
|
+
raise ValueError("Cached source identity does not match its key.")
|
|
65
|
+
files[entry.source_id] = source_file
|
|
66
|
+
hits += 1
|
|
67
|
+
except (TypeError, ValueError, ValidationError):
|
|
68
|
+
if cached.value is not None and not cached.invalidated:
|
|
69
|
+
self.storage.delete(options, key)
|
|
70
|
+
invalidated += int(cached.invalidated or cached.value is not None)
|
|
71
|
+
misses.append(entry.source_id)
|
|
72
|
+
|
|
73
|
+
if misses or not inventory.entries:
|
|
74
|
+
self.reader.ensure_available(request.runtime)
|
|
75
|
+
extracted = self.reader.extract_entries(request, inventory, tuple(misses))
|
|
76
|
+
for source_id in misses:
|
|
77
|
+
source_file = extracted.get(source_id)
|
|
78
|
+
if source_file is None:
|
|
79
|
+
raise RuntimeError(f"Extractor omitted a requested source file: {source_id}")
|
|
80
|
+
files[source_id] = source_file
|
|
81
|
+
self._write(options, keys[source_id], source_file.model_dump(mode="json"))
|
|
82
|
+
|
|
83
|
+
ordered_files = {entry.source_id: files[entry.source_id] for entry in inventory.entries}
|
|
84
|
+
modules: dict[ModuleId, FileId] = {}
|
|
85
|
+
for file_id, source_file in ordered_files.items():
|
|
86
|
+
existing = modules.get(source_file.module_id)
|
|
87
|
+
if existing is not None:
|
|
88
|
+
raise DuplicateIdentityError("module", source_file.module_id, existing, file_id)
|
|
89
|
+
modules[source_file.module_id] = file_id
|
|
90
|
+
|
|
91
|
+
extraction = SourceExtraction(
|
|
92
|
+
files=ordered_files,
|
|
93
|
+
modules=modules,
|
|
94
|
+
files_found=inventory.files_found,
|
|
95
|
+
files_excluded=inventory.files_excluded,
|
|
96
|
+
directories_pruned=inventory.directories_pruned,
|
|
97
|
+
)
|
|
98
|
+
manifest = self.identity.manifest(request, policy, inventory.entries)
|
|
99
|
+
self._write(
|
|
100
|
+
options,
|
|
101
|
+
manifest,
|
|
102
|
+
{
|
|
103
|
+
"sources": [
|
|
104
|
+
{
|
|
105
|
+
"relative_path": entry.relative_path,
|
|
106
|
+
"content_digest": entry.content_digest,
|
|
107
|
+
"source_key": keys[entry.source_id].digest,
|
|
108
|
+
}
|
|
109
|
+
for entry in inventory.entries
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
self.prune(options)
|
|
114
|
+
return CachedResult(
|
|
115
|
+
value=ExtractionSnapshot(extraction=extraction, manifest=manifest),
|
|
116
|
+
outcomes=(
|
|
117
|
+
CacheOutcome(
|
|
118
|
+
stage=CacheStage.EXTRACTION,
|
|
119
|
+
namespace=options.namespace,
|
|
120
|
+
hits=hits,
|
|
121
|
+
misses=len(misses),
|
|
122
|
+
invalidated=invalidated,
|
|
123
|
+
computed=len(misses),
|
|
124
|
+
stored=len(misses),
|
|
125
|
+
),
|
|
126
|
+
),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def code_map(self, snapshot: ExtractionSnapshot, options: CacheOptions) -> CachedResult[CodeMap | None]:
|
|
130
|
+
key = self.identity.code_map("", snapshot.manifest)
|
|
131
|
+
cached = self._read(options, key)
|
|
132
|
+
try:
|
|
133
|
+
value = CodeMap.model_validate(cached.value)
|
|
134
|
+
outcome = CacheOutcome(stage=CacheStage.CODE_MAP, namespace=options.namespace, hits=1)
|
|
135
|
+
except (TypeError, ValueError, ValidationError):
|
|
136
|
+
if cached.value is not None and not cached.invalidated:
|
|
137
|
+
self.storage.delete(options, key)
|
|
138
|
+
value = None
|
|
139
|
+
outcome = CacheOutcome(
|
|
140
|
+
stage=CacheStage.CODE_MAP,
|
|
141
|
+
namespace=options.namespace,
|
|
142
|
+
misses=1,
|
|
143
|
+
invalidated=int(cached.invalidated or cached.value is not None),
|
|
144
|
+
)
|
|
145
|
+
return CachedResult[CodeMap | None](value=value, outcomes=(outcome,))
|
|
146
|
+
|
|
147
|
+
def store_code_map(self, snapshot: ExtractionSnapshot, code_map: CodeMap, options: CacheOptions) -> None:
|
|
148
|
+
self._write(options, self.identity.code_map("", snapshot.manifest), code_map.model_dump(mode="json"))
|
|
149
|
+
self.prune(options)
|
|
150
|
+
|
|
151
|
+
def reports(
|
|
152
|
+
self, code_map: CodeMap, config: ArchitectureConfig, options: CacheOptions
|
|
153
|
+
) -> CachedResult[tuple[ReportNode, ...] | None]:
|
|
154
|
+
key = self.identity.reports(code_map, config)
|
|
155
|
+
cached = self._read(options, key)
|
|
156
|
+
cached_value: object | None = cached.value
|
|
157
|
+
invalidated = cached.invalidated or cached_value is not None
|
|
158
|
+
try:
|
|
159
|
+
if not isinstance(cached_value, list):
|
|
160
|
+
raise ValueError("Cached reports must be a list.")
|
|
161
|
+
reports = tuple(self._report(item) for item in cast(list[object], cached_value))
|
|
162
|
+
value = tuple(sorted(reports, key=lambda item: (item.metadata.order, item.metadata.id)))
|
|
163
|
+
outcome = CacheOutcome(stage=CacheStage.REPORTS, namespace=options.namespace, hits=1)
|
|
164
|
+
except (AttributeError, ImportError, KeyError, TypeError, ValueError, ValidationError):
|
|
165
|
+
if cached_value is not None and not cached.invalidated:
|
|
166
|
+
self.storage.delete(options, key)
|
|
167
|
+
value = None
|
|
168
|
+
outcome = CacheOutcome(
|
|
169
|
+
stage=CacheStage.REPORTS,
|
|
170
|
+
namespace=options.namespace,
|
|
171
|
+
misses=1,
|
|
172
|
+
invalidated=int(invalidated),
|
|
173
|
+
)
|
|
174
|
+
return CachedResult[tuple[ReportNode, ...] | None](value=value, outcomes=(outcome,))
|
|
175
|
+
|
|
176
|
+
def store_reports(
|
|
177
|
+
self,
|
|
178
|
+
code_map: CodeMap,
|
|
179
|
+
config: ArchitectureConfig,
|
|
180
|
+
reports: tuple[ReportNode, ...],
|
|
181
|
+
options: CacheOptions,
|
|
182
|
+
) -> None:
|
|
183
|
+
value = [
|
|
184
|
+
{
|
|
185
|
+
"model": f"{type(report).__module__}.{type(report).__qualname__}",
|
|
186
|
+
"payload": report.model_dump(mode="json", exclude_computed_fields=True),
|
|
187
|
+
}
|
|
188
|
+
for report in reports
|
|
189
|
+
]
|
|
190
|
+
self._write(options, self.identity.reports(code_map, config), value)
|
|
191
|
+
self.prune(options)
|
|
192
|
+
|
|
193
|
+
def clear(self, options: CacheOptions) -> None:
|
|
194
|
+
self.storage.clear(options)
|
|
195
|
+
|
|
196
|
+
def prune(self, options: CacheOptions) -> None:
|
|
197
|
+
entries = self.storage.entries(options)
|
|
198
|
+
total = sum(entry.size for entry in entries)
|
|
199
|
+
for entry in sorted(entries, key=lambda item: (item.last_access_ns, item.key.kind, item.key.digest)):
|
|
200
|
+
if total <= options.max_bytes:
|
|
201
|
+
break
|
|
202
|
+
self.storage.delete(options, entry.key)
|
|
203
|
+
total -= entry.size
|
|
204
|
+
|
|
205
|
+
def _read(self, options: CacheOptions, key: CacheKey) -> _CacheRead:
|
|
206
|
+
payload = self.storage.read(options, key)
|
|
207
|
+
if payload is None:
|
|
208
|
+
return _CacheRead(value=None, invalidated=False)
|
|
209
|
+
value = self.codec.decode(key, payload)
|
|
210
|
+
if value is None:
|
|
211
|
+
self.storage.delete(options, key)
|
|
212
|
+
return _CacheRead(value=None, invalidated=True)
|
|
213
|
+
return _CacheRead(value=value, invalidated=False)
|
|
214
|
+
|
|
215
|
+
def _write(self, options: CacheOptions, key: CacheKey, value: object) -> None:
|
|
216
|
+
self.storage.write(options, key, self.codec.encode(key, value))
|
|
217
|
+
|
|
218
|
+
def _report(self, value: object) -> ReportNode:
|
|
219
|
+
if not isinstance(value, dict):
|
|
220
|
+
raise ValueError("Cached report entry must be an object.")
|
|
221
|
+
entry = cast(dict[str, object], value)
|
|
222
|
+
model_name = entry["model"]
|
|
223
|
+
payload = entry["payload"]
|
|
224
|
+
if not isinstance(model_name, str) or not model_name.startswith("modwire.architecture."):
|
|
225
|
+
raise ValueError("Cached report model is outside the architecture package.")
|
|
226
|
+
module_name, _, class_name = model_name.rpartition(".")
|
|
227
|
+
model: Any = getattr(importlib.import_module(module_name), class_name)
|
|
228
|
+
if not isinstance(model, type) or not issubclass(model, BaseModel) or not issubclass(model, ReportNode):
|
|
229
|
+
raise ValueError("Cached report model is not a report node.")
|
|
230
|
+
return model.model_validate(payload)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from .models.cache_entry import CacheEntry
|
|
4
|
+
from .models.cache_key import CacheKey
|
|
5
|
+
from .models.cache_options import CacheOptions
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CacheStorage(ABC):
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def read(self, options: CacheOptions, key: CacheKey) -> bytes | None:
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def write(self, options: CacheOptions, key: CacheKey, payload: bytes) -> None:
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def entries(self, options: CacheOptions) -> tuple[CacheEntry, ...]:
|
|
19
|
+
raise NotImplementedError
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def delete(self, options: CacheOptions, key: CacheKey) -> None:
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def clear(self, options: CacheOptions) -> None:
|
|
27
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from ....shared.values.models.value_model import ValueModel
|
|
4
|
+
|
|
5
|
+
type CacheKind = Literal["source", "manifest", "code-map", "reports"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CacheKey(ValueModel):
|
|
9
|
+
schema_version: Literal[1] = 1
|
|
10
|
+
kind: CacheKind
|
|
11
|
+
digest: str
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from pydantic import field_validator
|
|
2
|
+
|
|
3
|
+
from ....shared.values.models.value_model import ValueModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CacheOptions(ValueModel):
|
|
7
|
+
"""Generic persistent-cache settings supplied by a caller."""
|
|
8
|
+
|
|
9
|
+
directory: str
|
|
10
|
+
namespace: str
|
|
11
|
+
max_bytes: int
|
|
12
|
+
|
|
13
|
+
@field_validator("directory", "namespace")
|
|
14
|
+
@classmethod
|
|
15
|
+
def _non_empty(cls, value: str) -> str:
|
|
16
|
+
if not value.strip():
|
|
17
|
+
raise ValueError("Cache directory and namespace must not be empty.")
|
|
18
|
+
return value
|
|
19
|
+
|
|
20
|
+
@field_validator("max_bytes")
|
|
21
|
+
@classmethod
|
|
22
|
+
def _positive_size(cls, value: int) -> int:
|
|
23
|
+
if value < 1:
|
|
24
|
+
raise ValueError("Cache max_bytes must be at least one.")
|
|
25
|
+
return value
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
3
|
+
from pydantic import field_validator
|
|
4
|
+
|
|
5
|
+
from ....shared.values.models.value_model import ValueModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CacheStage(StrEnum):
|
|
9
|
+
"""Public stages reported by cached Modwire operations."""
|
|
10
|
+
|
|
11
|
+
EXTRACTION = "extraction"
|
|
12
|
+
CODE_MAP = "code-map"
|
|
13
|
+
REPORTS = "reports"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CacheOutcome(ValueModel):
|
|
17
|
+
"""Content-safe lifecycle counts for one stage of a cached operation.
|
|
18
|
+
|
|
19
|
+
Extraction counts describe current source records. Code-map and report counts
|
|
20
|
+
describe one entry. Invalidated entries are also misses. Diagnostics include
|
|
21
|
+
the configured namespace but never cache keys, source identities, or content.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
stage: CacheStage
|
|
25
|
+
namespace: str
|
|
26
|
+
hits: int = 0
|
|
27
|
+
misses: int = 0
|
|
28
|
+
invalidated: int = 0
|
|
29
|
+
computed: int = 0
|
|
30
|
+
stored: int = 0
|
|
31
|
+
|
|
32
|
+
@field_validator("namespace")
|
|
33
|
+
@classmethod
|
|
34
|
+
def _non_empty_namespace(cls, value: str) -> str:
|
|
35
|
+
if not value.strip():
|
|
36
|
+
raise ValueError("Cache outcome namespace must not be empty.")
|
|
37
|
+
return value
|
|
38
|
+
|
|
39
|
+
@field_validator("hits", "misses", "invalidated", "computed", "stored")
|
|
40
|
+
@classmethod
|
|
41
|
+
def _non_negative_count(cls, value: int) -> int:
|
|
42
|
+
if value < 0:
|
|
43
|
+
raise ValueError("Cache outcome counts must not be negative.")
|
|
44
|
+
return value
|