modwire 9.0.0__tar.gz → 9.1.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.
Files changed (361) hide show
  1. {modwire-9.0.0 → modwire-9.1.0}/.dev/modwire.egg-info/SOURCES.txt +17 -0
  2. {modwire-9.0.0 → modwire-9.1.0}/Makefile +4 -1
  3. {modwire-9.0.0 → modwire-9.1.0}/PKG-INFO +21 -1
  4. {modwire-9.0.0 → modwire-9.1.0}/README.md +20 -0
  5. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/application.py +39 -2
  6. modwire-9.1.0/src/modwire/cli/cache/application.py +183 -0
  7. modwire-9.1.0/src/modwire/cli/cache/domain.py +27 -0
  8. modwire-9.1.0/src/modwire/cli/cache/models/cache_entry.py +8 -0
  9. modwire-9.1.0/src/modwire/cli/cache/models/cache_key.py +11 -0
  10. modwire-9.1.0/src/modwire/cli/cache/models/cache_options.py +25 -0
  11. modwire-9.1.0/src/modwire/cli/cache/models/extraction_snapshot.py +8 -0
  12. modwire-9.1.0/src/modwire/cli/cache/models/source_entry.py +9 -0
  13. modwire-9.1.0/src/modwire/cli/cache/models/source_inventory.py +9 -0
  14. modwire-9.1.0/src/modwire/cli/cache/services/cache_codec.py +40 -0
  15. modwire-9.1.0/src/modwire/cli/cache/services/cache_identity.py +106 -0
  16. modwire-9.1.0/src/modwire/cli/cache/services/filesystem_cache_storage.py +147 -0
  17. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/facade.py +59 -6
  18. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/domain.py +13 -0
  19. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/command_request.py +5 -1
  20. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/batch_source_reader.py +57 -15
  21. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/command_line.py +11 -1
  22. modwire-9.1.0/tests/application/test_07_cache.py +143 -0
  23. modwire-9.1.0/tests/extraction/cache_benchmark/run.py +155 -0
  24. modwire-9.1.0/tests/extraction/scan_benchmark/__init__.py +0 -0
  25. modwire-9.1.0/tests/shared/__init__.py +0 -0
  26. modwire-9.1.0/tests/shared/code/__init__.py +0 -0
  27. modwire-9.1.0/tests/support/__init__.py +0 -0
  28. {modwire-9.0.0 → modwire-9.1.0}/.github/workflows/ci.yml +0 -0
  29. {modwire-9.0.0 → modwire-9.1.0}/.github/workflows/release.yml +0 -0
  30. {modwire-9.0.0 → modwire-9.1.0}/.gitignore +0 -0
  31. {modwire-9.0.0 → modwire-9.1.0}/AGENTS.md +0 -0
  32. {modwire-9.0.0 → modwire-9.1.0}/LICENSE +0 -0
  33. {modwire-9.0.0 → modwire-9.1.0}/MANIFEST.in +0 -0
  34. {modwire-9.0.0 → modwire-9.1.0}/docs/target-language-ownership.md +0 -0
  35. {modwire-9.0.0 → modwire-9.1.0}/pyproject.toml +0 -0
  36. {modwire-9.0.0 → modwire-9.1.0}/scripts/check_extractors.py +0 -0
  37. {modwire-9.0.0 → modwire-9.1.0}/scripts/generate_docs.py +0 -0
  38. {modwire-9.0.0 → modwire-9.1.0}/scripts/verify_consumer.py +0 -0
  39. {modwire-9.0.0 → modwire-9.1.0}/setup.cfg +0 -0
  40. {modwire-9.0.0 → modwire-9.1.0}/setup.py +0 -0
  41. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/__init__.py +0 -0
  42. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/__main__.py +0 -0
  43. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/__init__.py +0 -0
  44. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/__init__.py +0 -0
  45. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/application.py +0 -0
  46. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/domain.py +0 -0
  47. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/__init__.py +0 -0
  48. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/edge_rule_violation.py +0 -0
  49. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/flow_report.py +0 -0
  50. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/flow_violation.py +0 -0
  51. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/types.py +0 -0
  52. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/__init__.py +0 -0
  53. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/backward_flow_analyzer.py +0 -0
  54. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/boundaries_flow_analyzer.py +0 -0
  55. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/module_boundary_analyzer.py +0 -0
  56. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/no_cycles_flow_analyzer.py +0 -0
  57. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/no_reentry_flow_analyzer.py +0 -0
  58. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/__init__.py +0 -0
  59. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/application.py +0 -0
  60. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/__init__.py +0 -0
  61. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/architecture_config.py +0 -0
  62. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/boundaries_config.py +0 -0
  63. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/boundary_rule.py +0 -0
  64. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/configuration_value.py +0 -0
  65. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/flow_realm.py +0 -0
  66. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/flow_rules.py +0 -0
  67. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/shape_config.py +0 -0
  68. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/shape_realm.py +0 -0
  69. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/shape_rules.py +0 -0
  70. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/tag_rule.py +0 -0
  71. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/facade.py +0 -0
  72. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/__init__.py +0 -0
  73. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/application.py +0 -0
  74. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/domain.py +0 -0
  75. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/__init__.py +0 -0
  76. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/callable_report_entry.py +0 -0
  77. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/callables_report.py +0 -0
  78. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/clusters_report.py +0 -0
  79. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/clusters_report_item.py +0 -0
  80. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/coherence_report.py +0 -0
  81. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/exports_report.py +0 -0
  82. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/exports_report_item.py +0 -0
  83. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/hotspots_report.py +0 -0
  84. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/hotspots_report_item.py +0 -0
  85. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/insight_report.py +0 -0
  86. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/__init__.py +0 -0
  87. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/callables_reporter.py +0 -0
  88. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/clusters_reporter.py +0 -0
  89. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/coherence_reporter.py +0 -0
  90. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/exports_reporter.py +0 -0
  91. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/hotspots_reporter.py +0 -0
  92. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/insight_report_field_map.py +0 -0
  93. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/__init__.py +0 -0
  94. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/application.py +0 -0
  95. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/domain.py +0 -0
  96. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/__init__.py +0 -0
  97. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/architecture_map.py +0 -0
  98. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/architecture_realm.py +0 -0
  99. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/tag_map.py +0 -0
  100. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/tag_match.py +0 -0
  101. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/services/__init__.py +0 -0
  102. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/services/architecture_map_loader.py +0 -0
  103. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/services/tag_matcher.py +0 -0
  104. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/__init__.py +0 -0
  105. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/application.py +0 -0
  106. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/domain.py +0 -0
  107. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/__init__.py +0 -0
  108. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/architecture_group.py +0 -0
  109. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/map_report.py +0 -0
  110. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_catalog.py +0 -0
  111. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_descriptor.py +0 -0
  112. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_item.py +0 -0
  113. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_metadata.py +0 -0
  114. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_node.py +0 -0
  115. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_section.py +0 -0
  116. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/services/__init__.py +0 -0
  117. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/services/map_report_collector.py +0 -0
  118. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/__init__.py +0 -0
  119. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/application.py +0 -0
  120. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/domain.py +0 -0
  121. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/models/__init__.py +0 -0
  122. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/models/shape_realm_architecture_map.py +0 -0
  123. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/models/shape_report.py +0 -0
  124. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/models/shape_violation.py +0 -0
  125. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/__init__.py +0 -0
  126. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/abstract_class_resolver.py +0 -0
  127. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/callable_resolver.py +0 -0
  128. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/class_resolver.py +0 -0
  129. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/file_resolver.py +0 -0
  130. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/import_resolver.py +0 -0
  131. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/property_resolver.py +0 -0
  132. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/signature_resolver.py +0 -0
  133. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/symbol_resolver.py +0 -0
  134. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/autowiring.py +0 -0
  135. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/__init__.py +0 -0
  136. {modwire-9.0.0/src/modwire/cli/resources/models → modwire-9.1.0/src/modwire/cli/cache}/__init__.py +0 -0
  137. {modwire-9.0.0/src/modwire/extraction → modwire-9.1.0/src/modwire/cli/cache/models}/__init__.py +0 -0
  138. {modwire-9.0.0/src/modwire/shared → modwire-9.1.0/src/modwire/cli/cache/services}/__init__.py +0 -0
  139. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/documentation/__init__.py +0 -0
  140. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/documentation/application.py +0 -0
  141. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/documentation/services/__init__.py +0 -0
  142. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/documentation/services/documentation_generator.py +0 -0
  143. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/__init__.py +0 -0
  144. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/application.py +0 -0
  145. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/models/__init__.py +0 -0
  146. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/models/initialization_result.py +0 -0
  147. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/services/__init__.py +0 -0
  148. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/services/initialization_service.py +0 -0
  149. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/__init__.py +0 -0
  150. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/application.py +0 -0
  151. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/__init__.py +0 -0
  152. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/extractor_batch_input.py +0 -0
  153. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/extractor_command_input.py +0 -0
  154. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/extractor_source_input.py +0 -0
  155. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/report_pipeline_context.py +0 -0
  156. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/scan_policy.py +0 -0
  157. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/__init__.py +0 -0
  158. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/callables_insight.py +0 -0
  159. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/clusters_insight.py +0 -0
  160. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/coherence_insight.py +0 -0
  161. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/configuration_loader.py +0 -0
  162. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/extractor_command.py +0 -0
  163. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/flow_violations.py +0 -0
  164. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/hotspots_insight.py +0 -0
  165. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/map_tree.py +0 -0
  166. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/output_console.py +0 -0
  167. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/shape_violations.py +0 -0
  168. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/success.py +0 -0
  169. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/unknown_files_warning.py +0 -0
  170. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/unused_exports_insight.py +0 -0
  171. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/__init__.py +0 -0
  172. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/application.py +0 -0
  173. {modwire-9.0.0/src/modwire/shared/values → modwire-9.1.0/src/modwire/cli/resources}/models/__init__.py +0 -0
  174. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/models/defaults.py +0 -0
  175. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/models/init_asset.py +0 -0
  176. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/AGENTS.md +0 -0
  177. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/ARCHITECTURE.md +0 -0
  178. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/INDEX.md +0 -0
  179. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/MODWIRE.md +0 -0
  180. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/RULES.md +0 -0
  181. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/TESTING.md +0 -0
  182. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/WORKFLOW.md +0 -0
  183. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/architecture.yaml +0 -0
  184. {modwire-9.0.0/tests → modwire-9.1.0/src/modwire/extraction}/__init__.py +0 -0
  185. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/__init__.py +0 -0
  186. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/application.py +0 -0
  187. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/domain.py +0 -0
  188. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/services/__init__.py +0 -0
  189. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/services/graph_builder.py +0 -0
  190. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/services/import_resolver.py +0 -0
  191. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/services/suffix_index.py +0 -0
  192. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/__init__.py +0 -0
  193. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/application.py +0 -0
  194. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/domain.py +0 -0
  195. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/__init__.py +0 -0
  196. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/batch_config.py +0 -0
  197. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/extraction_request.py +0 -0
  198. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/extractor_resource.py +0 -0
  199. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/extractor_runtime.py +0 -0
  200. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/python_call_context.py +0 -0
  201. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/__init__.py +0 -0
  202. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/build.php +0 -0
  203. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/build.py +0 -0
  204. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/composer.json +0 -0
  205. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/composer.lock +0 -0
  206. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/script.php +0 -0
  207. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/script.src.php +0 -0
  208. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/python/__init__.py +0 -0
  209. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/python/script.py +0 -0
  210. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/build.mjs +0 -0
  211. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/build.py +0 -0
  212. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/package-lock.json +0 -0
  213. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/package.json +0 -0
  214. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/script.js +0 -0
  215. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/script.ts +0 -0
  216. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/tsconfig.json +0 -0
  217. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/__init__.py +0 -0
  218. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/php_extractor.py +0 -0
  219. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/python_call_reader.py +0 -0
  220. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/python_extractor.py +0 -0
  221. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/python_syntax_parser.py +0 -0
  222. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/type_script_extractor.py +0 -0
  223. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/facade.py +0 -0
  224. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/py.typed +0 -0
  225. {modwire-9.0.0/tests/application → modwire-9.1.0/src/modwire/shared}/__init__.py +0 -0
  226. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/__init__.py +0 -0
  227. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/application.py +0 -0
  228. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/domain.py +0 -0
  229. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/__init__.py +0 -0
  230. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/code_map.py +0 -0
  231. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/code_package.py +0 -0
  232. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/dependency_edge_result.py +0 -0
  233. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/dependency_graph.py +0 -0
  234. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/dependency_node_result.py +0 -0
  235. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/duplicate_identity_error.py +0 -0
  236. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/edge.py +0 -0
  237. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/edge_resolution.py +0 -0
  238. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/identity.py +0 -0
  239. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/node.py +0 -0
  240. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/query_builder.py +0 -0
  241. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/query_types.py +0 -0
  242. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/queryable_code_map.py +0 -0
  243. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_abstract_class.py +0 -0
  244. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_call.py +0 -0
  245. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_callable.py +0 -0
  246. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_callable_symbol.py +0 -0
  247. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_class.py +0 -0
  248. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_class_method.py +0 -0
  249. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_class_property.py +0 -0
  250. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_export.py +0 -0
  251. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_extraction.py +0 -0
  252. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_file.py +0 -0
  253. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_file_result.py +0 -0
  254. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_function.py +0 -0
  255. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_import.py +0 -0
  256. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_imported_symbol.py +0 -0
  257. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_interface.py +0 -0
  258. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_item_result.py +0 -0
  259. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_parameter.py +0 -0
  260. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_signature.py +0 -0
  261. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_symbol.py +0 -0
  262. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_type.py +0 -0
  263. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_value.py +0 -0
  264. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/types.py +0 -0
  265. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/services/__init__.py +0 -0
  266. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/services/glob_path_matcher.py +0 -0
  267. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/services/identity_resolver.py +0 -0
  268. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/values/__init__.py +0 -0
  269. {modwire-9.0.0/tests/architecture → modwire-9.1.0/src/modwire/shared/values/models}/__init__.py +0 -0
  270. {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/values/models/value_model.py +0 -0
  271. {modwire-9.0.0/tests/architecture/boundaries → modwire-9.1.0/tests}/__init__.py +0 -0
  272. {modwire-9.0.0/tests/architecture/config → modwire-9.1.0/tests/application}/__init__.py +0 -0
  273. {modwire-9.0.0 → modwire-9.1.0}/tests/application/base_test.py +0 -0
  274. {modwire-9.0.0 → modwire-9.1.0}/tests/application/test_01_attacks.py +0 -0
  275. {modwire-9.0.0 → modwire-9.1.0}/tests/application/test_06_happy_path.py +0 -0
  276. {modwire-9.0.0/tests/architecture/insights → modwire-9.1.0/tests/architecture}/__init__.py +0 -0
  277. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/base_test.py +0 -0
  278. {modwire-9.0.0/tests/architecture/map → modwire-9.1.0/tests/architecture/boundaries}/__init__.py +0 -0
  279. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/base_test.py +0 -0
  280. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/test_01_attacks.py +0 -0
  281. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/test_02_invariants.py +0 -0
  282. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/test_03_public_api.py +0 -0
  283. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/test_04_paths.py +0 -0
  284. {modwire-9.0.0/tests/architecture/report → modwire-9.1.0/tests/architecture/config}/__init__.py +0 -0
  285. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/config/test_01_attacks.py +0 -0
  286. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/config/test_02_invariants.py +0 -0
  287. {modwire-9.0.0/tests/architecture/shape → modwire-9.1.0/tests/architecture/insights}/__init__.py +0 -0
  288. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/insights/base_test.py +0 -0
  289. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/insights/test_02_invariants.py +0 -0
  290. {modwire-9.0.0/tests/cli → modwire-9.1.0/tests/architecture/map}/__init__.py +0 -0
  291. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/map/test_02_patterns.py +0 -0
  292. {modwire-9.0.0/tests/cli/documentation → modwire-9.1.0/tests/architecture/report}/__init__.py +0 -0
  293. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/report/test_02_invariants.py +0 -0
  294. {modwire-9.0.0/tests/cli/initialization → modwire-9.1.0/tests/architecture/shape}/__init__.py +0 -0
  295. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/shape/base_test.py +0 -0
  296. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/shape/test_01_limits.py +0 -0
  297. {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/shape/test_02_invariants.py +0 -0
  298. {modwire-9.0.0/tests/cli/pipeline → modwire-9.1.0/tests/cli}/__init__.py +0 -0
  299. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/base_test.py +0 -0
  300. {modwire-9.0.0/tests/extraction → modwire-9.1.0/tests/cli/documentation}/__init__.py +0 -0
  301. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/documentation/test_02_invariants.py +0 -0
  302. {modwire-9.0.0/tests/extraction/big_projects → modwire-9.1.0/tests/cli/initialization}/__init__.py +0 -0
  303. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_01_attacks.py +0 -0
  304. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_02_invariants.py +0 -0
  305. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_03_interruption.py +0 -0
  306. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_04_cleanup.py +0 -0
  307. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_05_recovery.py +0 -0
  308. {modwire-9.0.0/tests/extraction/dependency → modwire-9.1.0/tests/cli/pipeline}/__init__.py +0 -0
  309. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/base_test.py +0 -0
  310. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_01_attacks.py +0 -0
  311. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_02_invariants.py +0 -0
  312. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_03_interruption.py +0 -0
  313. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_04_command_transport.py +0 -0
  314. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_05_recovery.py +0 -0
  315. {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_06_happy_path.py +0 -0
  316. {modwire-9.0.0 → modwire-9.1.0}/tests/conftest.py +0 -0
  317. {modwire-9.0.0/tests/extraction/extractors → modwire-9.1.0/tests/extraction}/__init__.py +0 -0
  318. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/base_test.py +0 -0
  319. {modwire-9.0.0/tests/extraction/scan_benchmark → modwire-9.1.0/tests/extraction/big_projects}/__init__.py +0 -0
  320. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/project.py +0 -0
  321. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/projects.json +0 -0
  322. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/resolution_results.json +0 -0
  323. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/results.json +0 -0
  324. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/run.py +0 -0
  325. {modwire-9.0.0/tests/shared → modwire-9.1.0/tests/extraction/cache_benchmark}/__init__.py +0 -0
  326. {modwire-9.0.0/tests/shared/code → modwire-9.1.0/tests/extraction/dependency}/__init__.py +0 -0
  327. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/dependency/test_02_invariants.py +0 -0
  328. {modwire-9.0.0/tests/support → modwire-9.1.0/tests/extraction/extractors}/__init__.py +0 -0
  329. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/extractors/test_01_attacks.py +0 -0
  330. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/extractors/test_02_invariants.py +0 -0
  331. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/extractors/test_03_native_symbols.py +0 -0
  332. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/scan_benchmark/prepare.py +0 -0
  333. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/scan_benchmark/results.json +0 -0
  334. {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/scan_benchmark/run.py +0 -0
  335. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/ignored/example_generated.php +0 -0
  336. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/src/example_application/example_actions/example_action.php +0 -0
  337. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/src/example_domain/example_model/example_record.php +0 -0
  338. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/src/example_domain/example_services/example_policy.php +0 -0
  339. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/src/example_interfaces/example_http/example_controller.php +0 -0
  340. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/ignored/example_generated.py +0 -0
  341. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/src/example_application/example_actions/example_action.py +0 -0
  342. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/src/example_domain/example_model/example_record.py +0 -0
  343. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/src/example_domain/example_services/example_policy.py +0 -0
  344. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/src/example_interfaces/example_http/example_controller.py +0 -0
  345. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/ignored/example_generated.ts +0 -0
  346. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_application/example_actions/example_action.ts +0 -0
  347. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_record.ts +0 -0
  348. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_view.tsx +0 -0
  349. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_audit.js +0 -0
  350. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_callables.ts +0 -0
  351. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_policy.ts +0 -0
  352. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_controller.ts +0 -0
  353. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_view.jsx +0 -0
  354. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/syntax/php/example_shapes.php +0 -0
  355. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/syntax/python/example_shapes.py +0 -0
  356. {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/syntax/typescript/example_shapes.ts +0 -0
  357. {modwire-9.0.0 → modwire-9.1.0}/tests/shared/code/test_02_invariants.py +0 -0
  358. {modwire-9.0.0 → modwire-9.1.0}/tests/support/base_test.py +0 -0
  359. {modwire-9.0.0 → modwire-9.1.0}/tests/support/code_map.py +0 -0
  360. {modwire-9.0.0 → modwire-9.1.0}/tests/support/service_test.py +0 -0
  361. {modwire-9.0.0 → modwire-9.1.0}/uv.lock +0 -0
@@ -112,6 +112,20 @@ 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/extraction_snapshot.py
123
+ src/modwire/cli/cache/models/source_entry.py
124
+ src/modwire/cli/cache/models/source_inventory.py
125
+ src/modwire/cli/cache/services/__init__.py
126
+ src/modwire/cli/cache/services/cache_codec.py
127
+ src/modwire/cli/cache/services/cache_identity.py
128
+ src/modwire/cli/cache/services/filesystem_cache_storage.py
115
129
  src/modwire/cli/documentation/__init__.py
116
130
  src/modwire/cli/documentation/application.py
117
131
  src/modwire/cli/documentation/services/__init__.py
@@ -253,6 +267,7 @@ tests/application/__init__.py
253
267
  tests/application/base_test.py
254
268
  tests/application/test_01_attacks.py
255
269
  tests/application/test_06_happy_path.py
270
+ tests/application/test_07_cache.py
256
271
  tests/architecture/__init__.py
257
272
  tests/architecture/base_test.py
258
273
  tests/architecture/boundaries/__init__.py
@@ -301,6 +316,8 @@ tests/extraction/big_projects/projects.json
301
316
  tests/extraction/big_projects/resolution_results.json
302
317
  tests/extraction/big_projects/results.json
303
318
  tests/extraction/big_projects/run.py
319
+ tests/extraction/cache_benchmark/__init__.py
320
+ tests/extraction/cache_benchmark/run.py
304
321
  tests/extraction/dependency/__init__.py
305
322
  tests/extraction/dependency/test_02_invariants.py
306
323
  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.0.0
3
+ Version: 9.1.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,10 @@ 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
+
51
55
  ### `discover`
52
56
 
53
57
  Discover supported source languages beneath a root using the caller's scan policy.
@@ -64,6 +68,18 @@ descendants are deliberately unobserved and are not included in file counts.
64
68
 
65
69
  Extract source files and return a queryable code map.
66
70
 
71
+ ### `generate_map_cached`
72
+
73
+ Return a code map with content-addressed source and complete-manifest reuse.
74
+
75
+ ### `generate_queryable_map_cached`
76
+
77
+ Return a queryable code map with content-addressed persistent reuse.
78
+
79
+ ### `clear_cache`
80
+
81
+ Clear only the Modwire-owned directory for one cache namespace.
82
+
67
83
  ### `load_configuration`
68
84
 
69
85
  Load and validate an architecture configuration from a directory.
@@ -84,6 +100,10 @@ Run the native extractor transport for one supported language.
84
100
 
85
101
  Run the Modwire command line interface and return its process status.
86
102
 
103
+ ## `CacheOptions`
104
+
105
+ Generic persistent-cache settings supplied by a caller.
106
+
87
107
  ## `ScanPolicy`
88
108
 
89
109
  Caller-owned filesystem traversal policy with explicit exclusions and opt-in symlink following.
@@ -20,6 +20,10 @@ 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
+
23
27
  ### `discover`
24
28
 
25
29
  Discover supported source languages beneath a root using the caller's scan policy.
@@ -36,6 +40,18 @@ descendants are deliberately unobserved and are not included in file counts.
36
40
 
37
41
  Extract source files and return a queryable code map.
38
42
 
43
+ ### `generate_map_cached`
44
+
45
+ Return a code map with content-addressed source and complete-manifest reuse.
46
+
47
+ ### `generate_queryable_map_cached`
48
+
49
+ Return a queryable code map with content-addressed persistent reuse.
50
+
51
+ ### `clear_cache`
52
+
53
+ Clear only the Modwire-owned directory for one cache namespace.
54
+
39
55
  ### `load_configuration`
40
56
 
41
57
  Load and validate an architecture configuration from a directory.
@@ -56,6 +72,10 @@ Run the native extractor transport for one supported language.
56
72
 
57
73
  Run the Modwire command line interface and return its process status.
58
74
 
75
+ ## `CacheOptions`
76
+
77
+ Generic persistent-cache settings supplied by a caller.
78
+
59
79
  ## `ScanPolicy`
60
80
 
61
81
  Caller-owned filesystem traversal policy with explicit exclusions and opt-in symlink following.
@@ -10,13 +10,14 @@ 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
13
14
  from .cli.facade import CliFacade
14
15
  from .cli.pipeline.models.scan_policy import ScanPolicy
15
16
  from .extraction.facade import ExtractionFacade
16
17
  from .shared.code.models.code_map import CodeMap
17
18
  from .shared.code.models.queryable_code_map import QueryableCodeMap
18
19
 
19
- __all__ = ["CodeMap", "ModwireApplication", "QueryableCodeMap", "ScanPolicy"]
20
+ __all__ = ["CacheOptions", "CodeMap", "ModwireApplication", "QueryableCodeMap", "ScanPolicy"]
20
21
 
21
22
 
22
23
  @dataclass(frozen=True)
@@ -56,6 +57,18 @@ class ModwireApplication:
56
57
 
57
58
  return self.architecture.analyze(code_map, config)
58
59
 
60
+ def analyze_cached(
61
+ self, code_map: QueryableCodeMap, config: ArchitectureConfig, options: CacheOptions
62
+ ) -> tuple[ReportNode, ...]:
63
+ """Analyze a code map, reusing reports for an exact map and configuration identity."""
64
+
65
+ cached = self.cli.cached_reports(code_map.code_map, config, options)
66
+ if cached is not None:
67
+ return cached
68
+ reports = self.architecture.analyze(code_map, config)
69
+ self.cli.store_reports(code_map.code_map, config, reports, options)
70
+ return reports
71
+
59
72
  def discover(self, root: str, policy: ScanPolicy) -> tuple[str, ...]:
60
73
  """Discover supported source languages beneath a root using the caller's scan policy."""
61
74
 
@@ -81,6 +94,30 @@ class ModwireApplication:
81
94
 
82
95
  return QueryableCodeMap(code_map=self.generate_map(language, root, policy))
83
96
 
97
+ def generate_map_cached(self, language: str, root: str, policy: ScanPolicy, options: CacheOptions) -> CodeMap:
98
+ """Return a code map with content-addressed source and complete-manifest reuse."""
99
+
100
+ request = self.extraction.request(language, str(root))
101
+ snapshot = self.cli.extract_cached(request, policy, options)
102
+ cached = self.cli.cached_code_map(snapshot, options)
103
+ if cached is not None:
104
+ return cached
105
+ code_map = self.extraction.generate_map(language, snapshot.extraction)
106
+ self.cli.store_code_map(snapshot, code_map, options)
107
+ return code_map
108
+
109
+ def generate_queryable_map_cached(
110
+ self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
111
+ ) -> QueryableCodeMap:
112
+ """Return a queryable code map with content-addressed persistent reuse."""
113
+
114
+ return QueryableCodeMap(code_map=self.generate_map_cached(language, root, policy, options))
115
+
116
+ def clear_cache(self, options: CacheOptions) -> None:
117
+ """Clear only the Modwire-owned directory for one cache namespace."""
118
+
119
+ self.cli.clear_cache(options)
120
+
84
121
  def load_configuration(self, dot_dir: str) -> ArchitectureConfig:
85
122
  """Load and validate an architecture configuration from a directory."""
86
123
 
@@ -94,7 +131,7 @@ class ModwireApplication:
94
131
  def generate_documentation(self, readme: str, check: bool) -> int:
95
132
  """Generate this README from the published interface docstrings, or check that it is current."""
96
133
 
97
- return self.cli.generate_documentation(str(readme), (type(self), ScanPolicy), check)
134
+ return self.cli.generate_documentation(str(readme), (type(self), CacheOptions, ScanPolicy), check)
98
135
 
99
136
  def run_extractor(self, language: str) -> int:
100
137
  """Run the native extractor transport for one supported language."""
@@ -0,0 +1,183 @@
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.extraction_snapshot import ExtractionSnapshot
22
+ from .services.cache_codec import CacheCodec
23
+ from .services.cache_identity import CacheIdentity
24
+
25
+
26
+ @injectable
27
+ @dataclass(frozen=True)
28
+ class CacheApplication:
29
+ reader: SourceReader
30
+ storage: CacheStorage
31
+ identity: CacheIdentity
32
+ codec: CacheCodec
33
+
34
+ def has_source_files(self, request: ExtractionRequest, policy: ScanPolicy) -> bool:
35
+ return self.reader.has_source_files(request, policy)
36
+
37
+ def extract(self, request: ExtractionRequest, policy: ScanPolicy) -> SourceExtraction:
38
+ self.reader.ensure_available(request.runtime)
39
+ return self.reader.extract_source(request, policy)
40
+
41
+ def extract_cached(
42
+ self, request: ExtractionRequest, policy: ScanPolicy, options: CacheOptions
43
+ ) -> ExtractionSnapshot:
44
+ inventory = self.reader.inventory(request, policy)
45
+ keys = {entry.source_id: self.identity.source(request, policy, entry) for entry in inventory.entries}
46
+ files: dict[FileId, SourceFile] = {}
47
+ misses: list[FileId] = []
48
+ for entry in inventory.entries:
49
+ key = keys[entry.source_id]
50
+ value = self._read(options, key)
51
+ try:
52
+ source_file = SourceFile.model_validate(value)
53
+ if source_file.file_id != entry.source_id:
54
+ raise ValueError("Cached source identity does not match its key.")
55
+ files[entry.source_id] = source_file
56
+ except (TypeError, ValueError, ValidationError):
57
+ self.storage.delete(options, key)
58
+ misses.append(entry.source_id)
59
+
60
+ if misses or not inventory.entries:
61
+ self.reader.ensure_available(request.runtime)
62
+ extracted = self.reader.extract_entries(request, inventory, tuple(misses))
63
+ for source_id in misses:
64
+ source_file = extracted.get(source_id)
65
+ if source_file is None:
66
+ raise RuntimeError(f"Extractor omitted a requested source file: {source_id}")
67
+ files[source_id] = source_file
68
+ self._write(options, keys[source_id], source_file.model_dump(mode="json"))
69
+
70
+ ordered_files = {entry.source_id: files[entry.source_id] for entry in inventory.entries}
71
+ modules: dict[ModuleId, FileId] = {}
72
+ for file_id, source_file in ordered_files.items():
73
+ existing = modules.get(source_file.module_id)
74
+ if existing is not None:
75
+ raise DuplicateIdentityError("module", source_file.module_id, existing, file_id)
76
+ modules[source_file.module_id] = file_id
77
+
78
+ extraction = SourceExtraction(
79
+ files=ordered_files,
80
+ modules=modules,
81
+ files_found=inventory.files_found,
82
+ files_excluded=inventory.files_excluded,
83
+ directories_pruned=inventory.directories_pruned,
84
+ )
85
+ manifest = self.identity.manifest(request, policy, inventory.entries)
86
+ self._write(
87
+ options,
88
+ manifest,
89
+ {
90
+ "sources": [
91
+ {
92
+ "relative_path": entry.relative_path,
93
+ "content_digest": entry.content_digest,
94
+ "source_key": keys[entry.source_id].digest,
95
+ }
96
+ for entry in inventory.entries
97
+ ]
98
+ },
99
+ )
100
+ self.prune(options)
101
+ return ExtractionSnapshot(extraction=extraction, manifest=manifest)
102
+
103
+ def code_map(self, snapshot: ExtractionSnapshot, options: CacheOptions) -> CodeMap | None:
104
+ key = self.identity.code_map("", snapshot.manifest)
105
+ value = self._read(options, key)
106
+ try:
107
+ return CodeMap.model_validate(value)
108
+ except (TypeError, ValueError, ValidationError):
109
+ self.storage.delete(options, key)
110
+ return None
111
+
112
+ def store_code_map(self, snapshot: ExtractionSnapshot, code_map: CodeMap, options: CacheOptions) -> None:
113
+ self._write(options, self.identity.code_map("", snapshot.manifest), code_map.model_dump(mode="json"))
114
+ self.prune(options)
115
+
116
+ def reports(
117
+ self, code_map: CodeMap, config: ArchitectureConfig, options: CacheOptions
118
+ ) -> tuple[ReportNode, ...] | None:
119
+ key = self.identity.reports(code_map, config)
120
+ value = self._read(options, key)
121
+ try:
122
+ if not isinstance(value, list):
123
+ raise ValueError("Cached reports must be a list.")
124
+ reports = tuple(self._report(item) for item in cast(list[object], value))
125
+ return tuple(sorted(reports, key=lambda item: (item.metadata.order, item.metadata.id)))
126
+ except (AttributeError, ImportError, KeyError, TypeError, ValueError, ValidationError):
127
+ self.storage.delete(options, key)
128
+ return None
129
+
130
+ def store_reports(
131
+ self,
132
+ code_map: CodeMap,
133
+ config: ArchitectureConfig,
134
+ reports: tuple[ReportNode, ...],
135
+ options: CacheOptions,
136
+ ) -> None:
137
+ value = [
138
+ {
139
+ "model": f"{type(report).__module__}.{type(report).__qualname__}",
140
+ "payload": report.model_dump(mode="json", exclude_computed_fields=True),
141
+ }
142
+ for report in reports
143
+ ]
144
+ self._write(options, self.identity.reports(code_map, config), value)
145
+ self.prune(options)
146
+
147
+ def clear(self, options: CacheOptions) -> None:
148
+ self.storage.clear(options)
149
+
150
+ def prune(self, options: CacheOptions) -> None:
151
+ entries = self.storage.entries(options)
152
+ total = sum(entry.size for entry in entries)
153
+ for entry in sorted(entries, key=lambda item: (item.last_access_ns, item.key.kind, item.key.digest)):
154
+ if total <= options.max_bytes:
155
+ break
156
+ self.storage.delete(options, entry.key)
157
+ total -= entry.size
158
+
159
+ def _read(self, options: CacheOptions, key: CacheKey) -> object | None:
160
+ payload = self.storage.read(options, key)
161
+ if payload is None:
162
+ return None
163
+ value = self.codec.decode(key, payload)
164
+ if value is None:
165
+ self.storage.delete(options, key)
166
+ return value
167
+
168
+ def _write(self, options: CacheOptions, key: CacheKey, value: object) -> None:
169
+ self.storage.write(options, key, self.codec.encode(key, value))
170
+
171
+ def _report(self, value: object) -> ReportNode:
172
+ if not isinstance(value, dict):
173
+ raise ValueError("Cached report entry must be an object.")
174
+ entry = cast(dict[str, object], value)
175
+ model_name = entry["model"]
176
+ payload = entry["payload"]
177
+ if not isinstance(model_name, str) or not model_name.startswith("modwire.architecture."):
178
+ raise ValueError("Cached report model is outside the architecture package.")
179
+ module_name, _, class_name = model_name.rpartition(".")
180
+ model: Any = getattr(importlib.import_module(module_name), class_name)
181
+ if not isinstance(model, type) or not issubclass(model, BaseModel) or not issubclass(model, ReportNode):
182
+ raise ValueError("Cached report model is not a report node.")
183
+ 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,8 @@
1
+ from ....shared.values.models.value_model import ValueModel
2
+ from .cache_key import CacheKey
3
+
4
+
5
+ class CacheEntry(ValueModel):
6
+ key: CacheKey
7
+ size: int
8
+ last_access_ns: int
@@ -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,8 @@
1
+ from ....shared.code.models.source_extraction import SourceExtraction
2
+ from ....shared.values.models.value_model import ValueModel
3
+ from .cache_key import CacheKey
4
+
5
+
6
+ class ExtractionSnapshot(ValueModel):
7
+ extraction: SourceExtraction
8
+ manifest: CacheKey
@@ -0,0 +1,9 @@
1
+ from ....shared.code.models.identity import FileId
2
+ from ....shared.values.models.value_model import ValueModel
3
+
4
+
5
+ class SourceEntry(ValueModel):
6
+ source_id: FileId
7
+ relative_path: str
8
+ content_digest: str
9
+ path: str
@@ -0,0 +1,9 @@
1
+ from ....shared.values.models.value_model import ValueModel
2
+ from .source_entry import SourceEntry
3
+
4
+
5
+ class SourceInventory(ValueModel):
6
+ entries: tuple[SourceEntry, ...]
7
+ files_found: int
8
+ files_excluded: int
9
+ directories_pruned: int
@@ -0,0 +1,40 @@
1
+ import hashlib
2
+ import json
3
+ from dataclasses import dataclass
4
+ from typing import Any, cast
5
+
6
+ from wireup import injectable
7
+
8
+ from ..models.cache_key import CacheKey
9
+
10
+
11
+ @injectable
12
+ @dataclass(frozen=True)
13
+ class CacheCodec:
14
+ def encode(self, key: CacheKey, value: object) -> bytes:
15
+ payload = json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
16
+ envelope = {
17
+ "schema_version": key.schema_version,
18
+ "key": key.model_dump(mode="json"),
19
+ "payload_digest": hashlib.sha256(payload).hexdigest(),
20
+ "payload": value,
21
+ }
22
+ return json.dumps(envelope, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
23
+
24
+ def decode(self, key: CacheKey, payload: bytes) -> object | None:
25
+ try:
26
+ parsed: Any = json.loads(payload)
27
+ if not isinstance(parsed, dict):
28
+ return None
29
+ envelope = cast(dict[str, object], parsed)
30
+ if envelope.get("schema_version") != key.schema_version:
31
+ return None
32
+ if envelope.get("key") != key.model_dump(mode="json"):
33
+ return None
34
+ value = envelope["payload"]
35
+ serialized = json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
36
+ if envelope.get("payload_digest") != hashlib.sha256(serialized).hexdigest():
37
+ return None
38
+ return value
39
+ except (KeyError, TypeError, ValueError, UnicodeDecodeError):
40
+ return None
@@ -0,0 +1,106 @@
1
+ import hashlib
2
+ import json
3
+ from dataclasses import dataclass
4
+ from functools import lru_cache
5
+ from importlib import metadata, resources
6
+ from typing import Any, ClassVar
7
+
8
+ from wireup import injectable
9
+
10
+ from ....architecture.config.models.architecture_config import ArchitectureConfig
11
+ from ....extraction.extractors.models.extraction_request import ExtractionRequest
12
+ from ....shared.code.models.code_map import CodeMap
13
+ from ...cache.models.cache_key import CacheKey, CacheKind
14
+ from ...cache.models.source_entry import SourceEntry
15
+ from ...pipeline.models.scan_policy import ScanPolicy
16
+
17
+
18
+ @injectable
19
+ @dataclass(frozen=True)
20
+ class CacheIdentity:
21
+ SOURCE_VERSION: ClassVar[int] = 1
22
+ MANIFEST_VERSION: ClassVar[int] = 1
23
+ CODE_MAP_VERSION: ClassVar[int] = 1
24
+ REPORT_VERSION: ClassVar[int] = 1
25
+
26
+ def source(self, request: ExtractionRequest, policy: ScanPolicy, entry: SourceEntry) -> CacheKey:
27
+ return self._key(
28
+ "source",
29
+ {
30
+ "version": self.SOURCE_VERSION,
31
+ "package": self._package_version(),
32
+ "runtime": self._runtime_identity(request),
33
+ "scan_policy": policy.model_dump(mode="json"),
34
+ "relative_path": entry.relative_path,
35
+ "source_id": entry.source_id,
36
+ "content_digest": entry.content_digest,
37
+ },
38
+ )
39
+
40
+ def manifest(self, request: ExtractionRequest, policy: ScanPolicy, entries: tuple[SourceEntry, ...]) -> CacheKey:
41
+ sources = tuple(
42
+ {
43
+ "relative_path": entry.relative_path,
44
+ "content_digest": entry.content_digest,
45
+ "source_key": self.source(request, policy, entry).digest,
46
+ }
47
+ for entry in sorted(entries, key=lambda item: item.relative_path)
48
+ )
49
+ return self._key(
50
+ "manifest",
51
+ {
52
+ "version": self.MANIFEST_VERSION,
53
+ "package": self._package_version(),
54
+ "runtime": self._runtime_identity(request),
55
+ "scan_policy": policy.model_dump(mode="json"),
56
+ "sources": sources,
57
+ },
58
+ )
59
+
60
+ def code_map(self, language: str, manifest: CacheKey) -> CacheKey:
61
+ return self._key(
62
+ "code-map",
63
+ {
64
+ "version": self.CODE_MAP_VERSION,
65
+ "package": self._package_version(),
66
+ "code_map_schema": CodeMap.schema_version,
67
+ "language": language,
68
+ "manifest": manifest.model_dump(mode="json"),
69
+ },
70
+ )
71
+
72
+ def reports(self, code_map: CodeMap, config: ArchitectureConfig) -> CacheKey:
73
+ return self._key(
74
+ "reports",
75
+ {
76
+ "version": self.REPORT_VERSION,
77
+ "package": self._package_version(),
78
+ "code_map": code_map.model_dump(mode="json"),
79
+ "configuration": config.model_dump(mode="json"),
80
+ },
81
+ )
82
+
83
+ def _runtime_identity(self, request: ExtractionRequest) -> dict[str, object]:
84
+ runtime = request.runtime
85
+ return {
86
+ "runtime": runtime.model_dump(mode="json"),
87
+ "batch": request.batch_config.model_dump(mode="json"),
88
+ "resource_digest": self._resource_digest(runtime.resource.package, runtime.resource.path),
89
+ }
90
+
91
+ @lru_cache(maxsize=32)
92
+ def _resource_digest(self, package: str, path: str) -> str:
93
+ resource = resources.files(package).joinpath(path)
94
+ return hashlib.sha256(resource.read_bytes()).hexdigest()
95
+
96
+ @lru_cache(maxsize=1)
97
+ def _package_version(self) -> str:
98
+ try:
99
+ return metadata.version("modwire")
100
+ except metadata.PackageNotFoundError:
101
+ return "0+unknown"
102
+
103
+ def _key(self, kind: CacheKind, value: object) -> CacheKey:
104
+ payload: Any = value
105
+ serialized = json.dumps(payload, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
106
+ return CacheKey(kind=kind, digest=hashlib.sha256(serialized).hexdigest())