archunitpython 1.1.0__tar.gz → 1.1.1__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 (132) hide show
  1. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/workflows/docs.yaml +1 -1
  2. archunitpython-1.1.1/.releaserc.json +27 -0
  3. archunitpython-1.1.1/BACKLOG.md +62 -0
  4. {archunitpython-1.1.0 → archunitpython-1.1.1}/CHANGELOG.md +7 -0
  5. {archunitpython-1.1.0 → archunitpython-1.1.1}/CONTRIBUTING.md +1 -1
  6. {archunitpython-1.1.0 → archunitpython-1.1.1}/PKG-INFO +1 -1
  7. {archunitpython-1.1.0 → archunitpython-1.1.1}/pyproject.toml +3 -3
  8. archunitpython-1.1.1/research/product-direction/architecture-testing-landscape.md +56 -0
  9. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/__init__.py +1 -1
  10. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/integration/test_e2e.py +1 -3
  11. archunitpython-1.1.1/tests/test_setup.py +21 -0
  12. archunitpython-1.1.0/.releaserc.json +0 -27
  13. archunitpython-1.1.0/TODO.md +0 -18
  14. archunitpython-1.1.0/tests/test_setup.py +0 -7
  15. {archunitpython-1.1.0 → archunitpython-1.1.1}/.editorconfig +0 -0
  16. {archunitpython-1.1.0 → archunitpython-1.1.1}/.gitattributes +0 -0
  17. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  18. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
  19. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  20. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/ISSUE_TEMPLATE/question.md +0 -0
  21. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/PAGES.md +0 -0
  22. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/dependabot.yml +0 -0
  23. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/pull_request_template.md +0 -0
  24. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/workflows/integrate.yaml +0 -0
  25. {archunitpython-1.1.0 → archunitpython-1.1.1}/.github/workflows/stale.yaml +0 -0
  26. {archunitpython-1.1.0 → archunitpython-1.1.1}/.gitignore +0 -0
  27. {archunitpython-1.1.0 → archunitpython-1.1.1}/LICENSE +0 -0
  28. {archunitpython-1.1.0 → archunitpython-1.1.1}/README.md +0 -0
  29. {archunitpython-1.1.0 → archunitpython-1.1.1}/assets/logo-rounded.png +0 -0
  30. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/__init__.py +0 -0
  31. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/assertion/__init__.py +0 -0
  32. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/assertion/violation.py +0 -0
  33. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/error/__init__.py +0 -0
  34. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/error/errors.py +0 -0
  35. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/extraction/__init__.py +0 -0
  36. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/extraction/extract_graph.py +0 -0
  37. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/extraction/graph.py +0 -0
  38. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/fluentapi/__init__.py +0 -0
  39. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/fluentapi/checkable.py +0 -0
  40. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/logging/__init__.py +0 -0
  41. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/logging/types.py +0 -0
  42. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/pattern_matching.py +0 -0
  43. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/__init__.py +0 -0
  44. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/cycles/__init__.py +0 -0
  45. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/cycles/cycle_utils.py +0 -0
  46. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/cycles/cycles.py +0 -0
  47. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/cycles/johnsons_apsp.py +0 -0
  48. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/cycles/model.py +0 -0
  49. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/cycles/tarjan_scc.py +0 -0
  50. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/edge_projections.py +0 -0
  51. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/project_cycles.py +0 -0
  52. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/project_edges.py +0 -0
  53. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/project_nodes.py +0 -0
  54. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/projection/types.py +0 -0
  55. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/regex_factory.py +0 -0
  56. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/types.py +0 -0
  57. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/util/__init__.py +0 -0
  58. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/util/declaration_detector.py +0 -0
  59. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/common/util/logger.py +0 -0
  60. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/__init__.py +0 -0
  61. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/assertion/__init__.py +0 -0
  62. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/assertion/custom_file_logic.py +0 -0
  63. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/assertion/cycle_free.py +0 -0
  64. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/assertion/depend_on_external_modules.py +0 -0
  65. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/assertion/depend_on_files.py +0 -0
  66. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/assertion/matching_files.py +0 -0
  67. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/fluentapi/__init__.py +0 -0
  68. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/files/fluentapi/files.py +0 -0
  69. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/__init__.py +0 -0
  70. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/assertion/__init__.py +0 -0
  71. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/assertion/metric_thresholds.py +0 -0
  72. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/calculation/__init__.py +0 -0
  73. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/calculation/count.py +0 -0
  74. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/calculation/distance.py +0 -0
  75. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/calculation/lcom.py +0 -0
  76. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/common/__init__.py +0 -0
  77. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/common/types.py +0 -0
  78. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/extraction/__init__.py +0 -0
  79. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/extraction/extract_class_info.py +0 -0
  80. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/fluentapi/__init__.py +0 -0
  81. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/fluentapi/export_utils.py +0 -0
  82. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/fluentapi/metrics.py +0 -0
  83. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/metrics/projection/__init__.py +0 -0
  84. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/py.typed +0 -0
  85. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/__init__.py +0 -0
  86. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/assertion/__init__.py +0 -0
  87. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/assertion/admissible_edges.py +0 -0
  88. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/fluentapi/__init__.py +0 -0
  89. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/fluentapi/slices.py +0 -0
  90. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/projection/__init__.py +0 -0
  91. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/projection/slicing_projections.py +0 -0
  92. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/uml/__init__.py +0 -0
  93. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/uml/export_diagram.py +0 -0
  94. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/slices/uml/generate_rules.py +0 -0
  95. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/testing/__init__.py +0 -0
  96. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/testing/assertion.py +0 -0
  97. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/testing/common/__init__.py +0 -0
  98. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/testing/common/color_utils.py +0 -0
  99. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/testing/common/violation_factory.py +0 -0
  100. {archunitpython-1.1.0 → archunitpython-1.1.1}/src/archunitpython/testing/pytest_plugin/__init__.py +0 -0
  101. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/__init__.py +0 -0
  102. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/common/__init__.py +0 -0
  103. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/common/test_core_types.py +0 -0
  104. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/common/test_cycles.py +0 -0
  105. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/common/test_declaration_detector.py +0 -0
  106. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/common/test_extract_graph.py +0 -0
  107. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/common/test_logger.py +0 -0
  108. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/common/test_pattern_matching.py +0 -0
  109. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/common/test_projection.py +0 -0
  110. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/files/__init__.py +0 -0
  111. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/files/test_file_assertions.py +0 -0
  112. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/files/test_files_fluentapi.py +0 -0
  113. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/metrics_project/service.py +0 -0
  114. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/__init__.py +0 -0
  115. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/architecture.puml +0 -0
  116. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/controllers/__init__.py +0 -0
  117. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/controllers/controller.py +0 -0
  118. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/models/__init__.py +0 -0
  119. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/models/model.py +0 -0
  120. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/services/__init__.py +0 -0
  121. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/services/service.py +0 -0
  122. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/services/service_a.py +0 -0
  123. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/services/service_b.py +0 -0
  124. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/utils/__init__.py +0 -0
  125. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/fixtures/sample_project/utils/helpers.py +0 -0
  126. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/integration/__init__.py +0 -0
  127. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/metrics/__init__.py +0 -0
  128. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/metrics/test_export.py +0 -0
  129. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/metrics/test_metrics.py +0 -0
  130. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/metrics/test_metrics_fluentapi.py +0 -0
  131. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/slices/__init__.py +0 -0
  132. {archunitpython-1.1.0 → archunitpython-1.1.1}/tests/slices/test_slices.py +0 -0
@@ -41,7 +41,7 @@ jobs:
41
41
  uses: actions/configure-pages@v6
42
42
 
43
43
  - name: Upload artifact
44
- uses: actions/upload-pages-artifact@v4
44
+ uses: actions/upload-pages-artifact@v5
45
45
  with:
46
46
  path: './docs'
47
47
 
@@ -0,0 +1,27 @@
1
+ {
2
+ "branches": ["main"],
3
+ "plugins": [
4
+ "@semantic-release/commit-analyzer",
5
+ "@semantic-release/release-notes-generator",
6
+ [
7
+ "@semantic-release/changelog",
8
+ {
9
+ "changelogFile": "CHANGELOG.md"
10
+ }
11
+ ],
12
+ [
13
+ "@semantic-release/exec",
14
+ {
15
+ "prepareCmd": "python -c \"import re, pathlib; files=[('pyproject.toml', r'(?m)^version = \\\"[^\\\"]+\\\"$', 'version = \\\"${nextRelease.version}\\\"'), ('src/archunitpython/__init__.py', r'(?m)^__version__ = \\\"[^\\\"]+\\\"$', '__version__ = \\\"${nextRelease.version}\\\"')]; [pathlib.Path(path).write_text(re.sub(pattern, replacement, pathlib.Path(path).read_text())) for path, pattern, replacement in files]\""
16
+ }
17
+ ],
18
+ [
19
+ "@semantic-release/git",
20
+ {
21
+ "assets": ["pyproject.toml", "src/archunitpython/__init__.py", "CHANGELOG.md"],
22
+ "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
23
+ }
24
+ ],
25
+ "@semantic-release/github"
26
+ ]
27
+ }
@@ -0,0 +1,62 @@
1
+ # Backlog
2
+
3
+ This backlog collects product and maintenance ideas from project research.
4
+
5
+ ## P0 - Maintenance And Correctness
6
+
7
+ - Keep package metadata synchronized across `pyproject.toml`, `CHANGELOG.md`, and `src/archunitpython/__init__.py`.
8
+ - Keep tool configuration valid for the supported Python range, especially mypy and Ruff target versions.
9
+ - Add a release metadata check that fails when the exported `__version__` differs from the project version.
10
+ - Add CI jobs that run tests, Ruff, mypy, and a package build from a clean checkout.
11
+
12
+ ## P1 - Adoption Workflow
13
+
14
+ - Add an `.archignore` or similar file, modeled after `.gitignore`, for files that should never be analyzed.
15
+ - Add a `.because(...)` API so rules can carry user-facing rationale into failure messages and generated architecture documentation.
16
+ - Add configuration-file support for common rules, while keeping the fluent Python API as the primary interface.
17
+ - Add support for monorepo and multi-package Python projects.
18
+
19
+ ## P1 - Python Import Semantics
20
+
21
+ - Add support for namespace packages that do not contain `__init__.py`.
22
+ - Detect dynamic imports such as `importlib.import_module()` and `__import__()`.
23
+ - Detect conditional imports such as `try/except ImportError`.
24
+ - Add better `TYPE_CHECKING` import handling, including options to ignore, include, or report type-only imports separately.
25
+ - Improve external dependency rules so users can express allowed and forbidden third-party packages at module or slice level.
26
+ - Consider a public-interface rule inspired by Tach, where modules may only import through declared package APIs.
27
+
28
+ ## P1 - Reporting And Documentation
29
+
30
+ - Add comprehensive HTML reports with dependency graphs, metric charts, and zone visualization.
31
+ - Auto-generate architecture documentation based on tests and rule rationales.
32
+ - Make logged paths clickable in IDEs and common terminal integrations.
33
+ - Add PlantUML or Mermaid export for discovered architecture graphs.
34
+ - Improve metric export examples and document how metric thresholds should be selected.
35
+
36
+ ## P2 - Rule Surface
37
+
38
+ - Add first-class layered architecture helpers so common clean/hexagonal/layered rules require less boilerplate.
39
+ - Add slice isolation helpers for bounded contexts and modular monoliths.
40
+ - Add richer custom rule hooks for dependency edges, files, classes, and metrics.
41
+ - Add transitive dependency checks, especially for "domain must not transitively reach infrastructure" style rules.
42
+ - Add naming and placement conventions for classes/functions, not only files.
43
+
44
+ ## P2 - Performance And Scale
45
+
46
+ - Improve performance for very large projects through parallel file parsing.
47
+ - Add persistent graph caching with invalidation based on file mtimes or content hashes.
48
+ - Add benchmarks for small, medium, large, and monorepo-style projects.
49
+
50
+ ## P2 - Metrics
51
+
52
+ - Add more LCOM edge case handling.
53
+ - Add metric documentation with examples for good, suspicious, and failing values.
54
+ - Add trend-friendly metric exports for CI artifacts.
55
+ - Consider additional architecture metrics such as coupling counts per slice, fan-in/fan-out summaries, and instability per package.
56
+
57
+ ## P3 - Packaging And Docs
58
+
59
+ - Publish to PyPI as part of the release pipeline if this is not already automated.
60
+ - Add a Sphinx or MkDocs documentation site.
61
+ - Add a complete example repository or examples folder covering pytest, unittest, PlantUML, metrics, and CI.
62
+ - Add contribution guidance for new rule types and metric implementations.
@@ -1,3 +1,10 @@
1
+ ## [1.1.1](https://github.com/LukasNiessen/ArchUnitPython/compare/v1.1.0...v1.1.1) (2026-05-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **deps:** bump actions/upload-pages-artifact ([a4452fc](https://github.com/LukasNiessen/ArchUnitPython/commit/a4452fce2ce9428882cf686227de9f09cb6a21b1))
7
+
1
8
  # [1.1.0](https://github.com/LukasNiessen/ArchUnitPython/compare/v1.0.1...v1.1.0) (2026-04-26)
2
9
 
3
10
 
@@ -36,7 +36,7 @@ Releases are fully automated. When a PR is merged to `main`:
36
36
  1. CI runs lint + type checking + tests (across Python 3.10-3.13)
37
37
  2. If CI passes, [semantic-release](https://github.com/semantic-release/semantic-release) analyzes commit messages since the last release
38
38
  3. If there are `fix:` or `feat:` commits, it automatically:
39
- - Bumps the version in `pyproject.toml`
39
+ - Bumps the version in `pyproject.toml` and `src/archunitpython/__init__.py`
40
40
  - Updates `CHANGELOG.md`
41
41
  - Publishes to PyPI
42
42
  - Creates a GitHub release with release notes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: archunitpython
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: Architecture testing library for Python projects. Enforce dependency rules, detect cycles, validate metrics.
5
5
  Project-URL: Homepage, https://github.com/LukasNiessen/ArchUnitPython
6
6
  Project-URL: Repository, https://github.com/LukasNiessen/ArchUnitPython.git
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "archunitpython"
7
- version = "1.1.0"
7
+ version = "1.1.1"
8
8
  description = "Architecture testing library for Python projects. Enforce dependency rules, detect cycles, validate metrics."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -67,13 +67,13 @@ python_classes = ["Test*"]
67
67
  python_functions = ["test_*"]
68
68
 
69
69
  [tool.mypy]
70
- python_version = "1.1.0"
70
+ python_version = "3.10"
71
71
  strict = true
72
72
  warn_return_any = true
73
73
  warn_unused_configs = true
74
74
 
75
75
  [tool.ruff]
76
- target-version = "1.1.0"
76
+ target-version = "py310"
77
77
  line-length = 100
78
78
 
79
79
  [tool.ruff.lint]
@@ -0,0 +1,56 @@
1
+ # Architecture Testing Landscape
2
+
3
+ Research date: 2026-05-23
4
+
5
+ This document compares ArchUnitPython with architecture testing tools in the broader ecosystem and with Python-specific alternatives. It focuses on user-facing features that can inform product direction.
6
+
7
+ ## Current ArchUnitPython Position
8
+
9
+ ArchUnitPython already covers three valuable surfaces:
10
+
11
+ - File-level architecture rules through `project_files(...)`: dependency direction, cycle detection, naming/path conventions, external dependency checks, and custom file predicates.
12
+ - Slice-level architecture rules through `project_slices(...)`: slice extraction from path patterns or regexes, PlantUML diagram adherence, and forbidden slice dependencies.
13
+ - Code metrics through `metrics(...)`: count metrics, LCOM variants, abstractness, instability, distance from the main sequence, zone checks, and custom metrics.
14
+
15
+ That breadth makes the project closer to ArchUnit-style libraries than to pure import linters. The main gaps are around configuration ergonomics, reporting, incremental adoption, IDE/CI workflow polish, and deeper Python import semantics.
16
+
17
+ ## General Architecture Testing Players
18
+
19
+ | Tool | Ecosystem | Rule definition style | Dependency/layer rules | Cycles | Diagram support | Metrics | Reports/visualization | Notable strengths | ArchUnitPython comparison |
20
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
21
+ | [ArchUnit](https://www.archunit.org/userguide/html/000_Index.html) | Java | Fluent Java API, JUnit integrations | Yes: packages, classes, layers, slices | Yes | PlantUML component diagrams | Yes: software architecture metrics | Strong test failure output; mature JUnit support | Mature reference implementation with a broad rule model and mature JUnit workflow | ArchUnitPython mirrors the core idea and already has files/slices/metrics, but lacks class/member/annotation richness and mature import options |
22
+ | [ArchUnitNET](https://github.com/TNG/ArchUnitNET) | .NET | Fluent C# API with xUnit/NUnit/MSTest integrations | Yes: assemblies, namespaces, types, members | Yes | PlantUML support and diagram generation in the project ecosystem | Limited compared with ArchUnit | Test framework integrations | Strong .NET analogue to ArchUnit with many framework adapters | ArchUnitPython has stronger built-in code metrics, but less type/member-level expressiveness |
23
+ | [NetArchTest](https://github.com/BenMorris/NetArchTest) | .NET | Fluent C# API | Yes: namespace/type dependency and conventions | Not a primary differentiator | No first-class PlantUML in core | No | Policy results; test framework agnostic | Simple, widely adopted dependency/convention tests for .NET | ArchUnitPython is broader on cycles, slices, PlantUML, and metrics |
24
+ | [ts-arch](https://github.com/ts-arch/ts-arch) | TypeScript/JavaScript | Fluent API, Jest matcher | Yes: files, folders, slices | Yes | PlantUML diagram adherence | No | Jest-oriented failure output | Very close conceptual sibling: file API, slice API, PlantUML, NX monorepo support | ArchUnitPython has a similar surface plus metrics; ts-arch has stronger monorepo/NX positioning |
25
+ | [jQAssistant](https://jqassistant.github.io/jqassistant/current/) | Mostly JVM, plugin-based | Scanner + graph database + rule concepts/constraints | Yes, via graph rules and plugins | Yes, rule-dependent | Documentation validation and living documentation workflows | Software analytics via graph queries | Reports, server/explore mode, graph-backed analysis | Enterprise-scale scanning, graph exploration, living documentation, baseline management | ArchUnitPython is much lighter and easier to embed in tests, but lacks graph database exploration and living-doc workflows |
26
+
27
+ ## Python Architecture Testing Libraries
28
+
29
+ | Tool | Rule definition style | Dependency/layer rules | Cycles | External dependency rules | Diagram support | Metrics | Reports/visualization | Adoption workflow | How ArchUnitPython stacks up |
30
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
31
+ | [ArchUnitPython](https://github.com/LukasNiessen/ArchUnitPython) | Fluent Python API used from pytest/unittest/any test framework | Yes: file dependencies, external modules, slices, forbidden slice dependencies | Yes: file-level cycles | Yes: external module matching | Yes: PlantUML slice adherence | Yes: count, LCOM, distance, custom metrics | Experimental metric export; no full HTML report yet | Plain test functions; `assert_passes()` or `.check()` | Broadest feature mix among the Python tools reviewed, especially because metrics and PlantUML are built in |
32
+ | [Import Linter](https://import-linter.readthedocs.io/en/stable/index.html) | `.importlinter` configuration contracts plus CLI | Yes: forbidden, protected, layers, independence, acyclic siblings, custom contracts | Yes: acyclic siblings | Primarily first-party import contracts | No first-class PlantUML | No | Browser-based architecture UI | CLI, CI, config file, caching | More mature for config-driven import contracts and exploration; ArchUnitPython is more test-native and broader on metrics/PlantUML |
33
+ | [Tach](https://docs.gauge.sh/getting-started/introduction/) | `tach.toml` plus CLI commands | Yes: module dependencies and public interfaces | Dependency graph focused | Yes: `check-external` for third-party imports | No | No | `show`, `map`, `report`, VS Code integration | Incremental CLI workflow, sync, pre-commit/CI, public interface enforcement | Tach is stronger for modular-boundary workflow and public APIs; ArchUnitPython is stronger for test-suite rules, metrics, and diagram validation |
34
+ | [PyTestArch](https://zyskarch.github.io/pytestarch/latest/features/module_import_checks/) | Python query language evaluated in pytest | Yes: module dependency query language and layered architecture rules | Implicit through dependency rules; not positioned as a primary cycle API | Not a main focus | Yes: generates rules from PlantUML component diagrams | No | Optional matplotlib visualization | Pytest-centered evaluation structures | Similar to ArchUnitPython on Python tests and PlantUML; ArchUnitPython has simpler fluent API and built-in metrics |
35
+ | [pytest-archon](https://github.com/jwbargsten/pytest-archon) | Pytest-oriented architecture assertions | Yes: forbidden dependencies and project structure rules | Yes, positioned around avoiding cycles | Not a main differentiator | No | No | Pytest failure output | Lightweight pytest helper | ArchUnitPython is broader and more ArchUnit-like; pytest-archon is smaller and focused |
36
+
37
+ ## Product Takeaways
38
+
39
+ - ArchUnitPython should lean into being the ArchUnit-style Python test library, not just another import linter.
40
+ - The nearest feature gap against Python tools is not raw rule breadth; it is workflow: config files, ignore files, public interfaces, incremental adoption, reporting, and IDE/CI polish.
41
+ - Against ArchUnit and ArchUnitNET, the biggest long-term gaps are richer semantic model support, import semantics, and mature documentation/reporting.
42
+ - Metrics are a meaningful differentiator in the Python space and should be kept visible in docs and examples.
43
+
44
+ ## Sources
45
+
46
+ - ArchUnit User Guide: https://www.archunit.org/userguide/html/000_Index.html
47
+ - ArchUnitNET repository: https://github.com/TNG/ArchUnitNET
48
+ - NetArchTest repository: https://github.com/BenMorris/NetArchTest
49
+ - ts-arch repository: https://github.com/ts-arch/ts-arch
50
+ - jQAssistant User Manual: https://jqassistant.github.io/jqassistant/current/
51
+ - Import Linter documentation: https://import-linter.readthedocs.io/en/stable/index.html
52
+ - Tach documentation: https://docs.gauge.sh/getting-started/introduction/
53
+ - PyTestArch documentation: https://zyskarch.github.io/pytestarch/latest/features/module_import_checks/
54
+ - PyTestArch PlantUML documentation: https://zyskarch.github.io/pytestarch/latest/features/plantuml/
55
+ - PyTestArch visualization documentation: https://zyskarch.github.io/pytestarch/latest/features/visualization/
56
+ - pytest-archon repository: https://github.com/jwbargsten/pytest-archon
@@ -1,6 +1,6 @@
1
1
  """ArchUnitPython - Architecture testing library for Python projects."""
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "1.1.1"
4
4
 
5
5
  # Files API
6
6
  # Common
@@ -10,9 +10,7 @@ from archunitpython import (
10
10
  format_violations,
11
11
  metrics,
12
12
  project_files,
13
- project_slices,
14
13
  )
15
- from archunitpython.common.assertion.violation import EmptyTestViolation
16
14
  from archunitpython.files.assertion.cycle_free import ViolatingCycle
17
15
 
18
16
  FIXTURES_DIR = os.path.join(
@@ -54,7 +52,7 @@ class TestTopLevelImports:
54
52
  def test_version(self):
55
53
  import archunitpython
56
54
 
57
- assert archunitpython.__version__ == "1.0.0"
55
+ assert archunitpython.__version__
58
56
 
59
57
 
60
58
  class TestAssertPasses:
@@ -0,0 +1,21 @@
1
+ """Verify project setup is correct."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+
7
+ def test_import():
8
+ import archunitpython
9
+
10
+ assert archunitpython.__version__
11
+
12
+
13
+ def test_project_version_matches_package_version():
14
+ import archunitpython
15
+
16
+ project_root = Path(__file__).resolve().parents[1]
17
+ pyproject = (project_root / "pyproject.toml").read_text()
18
+ match = re.search(r'^version = "([^"]+)"$', pyproject, re.MULTILINE)
19
+
20
+ assert match is not None
21
+ assert archunitpython.__version__ == match.group(1)
@@ -1,27 +0,0 @@
1
- {
2
- "branches": ["main"],
3
- "plugins": [
4
- "@semantic-release/commit-analyzer",
5
- "@semantic-release/release-notes-generator",
6
- [
7
- "@semantic-release/changelog",
8
- {
9
- "changelogFile": "CHANGELOG.md"
10
- }
11
- ],
12
- [
13
- "@semantic-release/exec",
14
- {
15
- "prepareCmd": "python -c \"import re, pathlib; p=pathlib.Path('pyproject.toml'); p.write_text(re.sub(r'version = \\\"[^\\\"]+\\\"', f'version = \\\"${nextRelease.version}\\\"', p.read_text()))\""
16
- }
17
- ],
18
- [
19
- "@semantic-release/git",
20
- {
21
- "assets": ["pyproject.toml", "CHANGELOG.md"],
22
- "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
23
- }
24
- ],
25
- "@semantic-release/github"
26
- ]
27
- }
@@ -1,18 +0,0 @@
1
- # TODOs
2
-
3
- This is our _"backlog"_. Contributions are highly welcome.
4
-
5
- - Add an `.archignore` or similar a la `.gitignore` for files that should never be considered by our tests
6
- - Auto generate an architecture documentation based on the tests
7
- - Add a `.because(...)` function a la ArchUnit. Should be used for the error message in case of a failing test as well as for auto-generated arch docs
8
- - Add support for namespace packages (packages without `__init__.py`)
9
- - Detect dynamic imports (`importlib.import_module()`, `__import__()`)
10
- - Detect conditional imports (`try/except ImportError`)
11
- - Add `TYPE_CHECKING` import handling (currently detected but could be filtered separately)
12
- - Make logged paths clickable in IDEs (currently works in some terminals)
13
- - Improve performance for very large projects (parallel file parsing)
14
- - Add comprehensive HTML report with charts and zone visualization
15
- - Add more LCOM edge case handling
16
- - Add support for monorepo / multi-package Python projects
17
- - Publish to PyPI
18
- - Add Sphinx/MkDocs documentation site
@@ -1,7 +0,0 @@
1
- """Verify project setup is correct."""
2
-
3
-
4
- def test_import():
5
- import archunitpython
6
-
7
- assert archunitpython.__version__ == "1.0.0"
File without changes
File without changes