archunitpython 1.3.0__tar.gz → 1.4.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.
- {archunitpython-1.3.0 → archunitpython-1.4.0}/BACKLOG.md +1 -1
- {archunitpython-1.3.0 → archunitpython-1.4.0}/CHANGELOG.md +13 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/PKG-INFO +21 -3
- {archunitpython-1.3.0 → archunitpython-1.4.0}/README.md +20 -2
- {archunitpython-1.3.0 → archunitpython-1.4.0}/pyproject.toml +1 -1
- {archunitpython-1.3.0 → archunitpython-1.4.0}/scripts/check_release_metadata.py +1 -1
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/__init__.py +1 -1
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/extraction/extract_graph.py +79 -11
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/extraction/extract_class_info.py +6 -3
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/fluentapi/metrics.py +2 -2
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/common/test_declaration_detector.py +2 -2
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/common/test_extract_graph.py +68 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/common/test_logger.py +0 -4
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/files/test_file_assertions.py +0 -2
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/utils/helpers.py +5 -1
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/metrics/test_metrics.py +8 -9
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/metrics/test_metrics_fluentapi.py +26 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.editorconfig +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.gitattributes +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/CODEOWNERS +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/FUNDING.yml +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/PAGES.md +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/dependabot.yml +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/pull_request_template.md +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/workflows/docs.yaml +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/workflows/integrate.yaml +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.github/workflows/stale.yaml +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.gitignore +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/.releaserc.json +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/CONTRIBUTING.md +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/LICENSE +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/assets/logo-rounded.png +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/research/product-direction/architecture-testing-landscape.md +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/scripts/bump_release_version.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/assertion/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/assertion/violation.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/error/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/error/errors.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/extraction/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/extraction/graph.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/fluentapi/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/fluentapi/checkable.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/logging/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/logging/types.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/pattern_matching.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/cycles/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/cycles/cycle_utils.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/cycles/cycles.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/cycles/johnsons_apsp.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/cycles/model.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/cycles/tarjan_scc.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/edge_projections.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/project_cycles.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/project_edges.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/project_nodes.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/types.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/regex_factory.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/types.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/util/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/util/declaration_detector.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/util/logger.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/custom_file_logic.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/cycle_free.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/depend_on_external_modules.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/depend_on_files.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/matching_files.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/fluentapi/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/fluentapi/files.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/graph/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/graph/graph_reporter.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/layers/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/layers/assertion/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/layers/assertion/layer_dependencies.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/layers/fluentapi/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/layers/fluentapi/layers.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/assertion/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/assertion/metric_thresholds.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/calculation/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/calculation/count.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/calculation/distance.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/calculation/lcom.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/common/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/common/types.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/extraction/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/fluentapi/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/fluentapi/export_utils.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/projection/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/py.typed +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/assertion/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/assertion/admissible_edges.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/fluentapi/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/fluentapi/slices.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/projection/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/projection/slicing_projections.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/uml/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/uml/export_diagram.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/uml/generate_rules.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/assertion.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/common/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/common/color_utils.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/common/violation_factory.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/pytest_plugin/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/common/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/common/test_core_types.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/common/test_cycles.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/common/test_pattern_matching.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/common/test_projection.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/files/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/files/test_files_fluentapi.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/metrics_project/service.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/architecture.puml +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/controllers/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/controllers/controller.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/models/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/models/model.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/services/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/services/service.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/services/service_a.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/services/service_b.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/utils/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/graph/test_graph_reporter.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/integration/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/integration/test_e2e.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/layers/test_layers.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/metrics/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/metrics/test_export.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/slices/__init__.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/slices/test_slices.py +0 -0
- {archunitpython-1.3.0 → archunitpython-1.4.0}/tests/test_setup.py +0 -0
|
@@ -11,7 +11,7 @@ This backlog collects product and maintenance ideas from project research.
|
|
|
11
11
|
|
|
12
12
|
## P1 - Adoption Workflow
|
|
13
13
|
|
|
14
|
-
- Add an `.archignore` or similar file, modeled after `.gitignore`, for files that should never be analyzed.
|
|
14
|
+
- [x] Add an `.archignore` or similar file, modeled after `.gitignore`, for files that should never be analyzed.
|
|
15
15
|
- [x] Add a `.because(...)` API so rules can carry user-facing rationale into failure messages and generated architecture documentation.
|
|
16
16
|
- Add configuration-file support for common rules, while keeping the fluent Python API as the primary interface.
|
|
17
17
|
- Add support for monorepo and multi-package Python projects.
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
# [1.4.0](https://github.com/LukasNiessen/ArchUnitPython/compare/v1.3.0...v1.4.0) (2026-07-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* clarify metadata and exclude messages ([999bb68](https://github.com/LukasNiessen/ArchUnitPython/commit/999bb689594ff613b5f4445191509bcdaa9a514f))
|
|
7
|
+
* harden archignore loading ([ae88c93](https://github.com/LukasNiessen/ArchUnitPython/commit/ae88c932ae2838cff0eabab687ac948f4920c3eb))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* support archignore exclusions ([c51c401](https://github.com/LukasNiessen/ArchUnitPython/commit/c51c40148425b08ce0257d75dd95c996d0505b00))
|
|
13
|
+
|
|
1
14
|
# [1.3.0](https://github.com/LukasNiessen/ArchUnitPython/compare/v1.2.1...v1.3.0) (2026-07-05)
|
|
2
15
|
|
|
3
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: archunitpython
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
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
|
|
@@ -188,6 +188,24 @@ options = CheckOptions(
|
|
|
188
188
|
violations = rule.check(options)
|
|
189
189
|
```
|
|
190
190
|
|
|
191
|
+
### Excluding Files With `.archignore`
|
|
192
|
+
|
|
193
|
+
Add a `.archignore` file to your project root to permanently exclude generated or
|
|
194
|
+
irrelevant files from architecture checks and file-based metrics:
|
|
195
|
+
|
|
196
|
+
```gitignore
|
|
197
|
+
# Generated code
|
|
198
|
+
generated/
|
|
199
|
+
|
|
200
|
+
# Migration scripts
|
|
201
|
+
migrations/*.py
|
|
202
|
+
|
|
203
|
+
# A single root-level file
|
|
204
|
+
/legacy_adapter.py
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Patterns support comments, blank lines, glob syntax, root-relative paths, path
|
|
208
|
+
patterns, and directory patterns with a trailing `/`.
|
|
191
209
|
### Explaining Rules With `.because(...)`
|
|
192
210
|
|
|
193
211
|
Attach a rationale to a rule so failing assertions explain why the rule exists:
|
|
@@ -450,7 +468,7 @@ def test_no_forbidden_dependency():
|
|
|
450
468
|
|
|
451
469
|
Generate dependency graph reports in multiple formats and narrow them to the part of the codebase you want to inspect.
|
|
452
470
|
|
|
453
|
-
**Using `requests` library repo for example**
|
|
471
|
+
**Using [`requests`](https://github.com/psf/requests) library repo for example**
|
|
454
472
|
|
|
455
473
|
```python
|
|
456
474
|
from archunitpython import project_graph
|
|
@@ -463,7 +481,7 @@ def test_export_dependency_graph_reports():
|
|
|
463
481
|
if __name__ == "__main__":
|
|
464
482
|
test_export_dependency_graph_reports()
|
|
465
483
|
```
|
|
466
|
-
**
|
|
484
|
+
**Exported mermaid diagram**
|
|
467
485
|
``` mermaid
|
|
468
486
|
flowchart LR
|
|
469
487
|
n0["__init__.py"]
|
|
@@ -155,6 +155,24 @@ options = CheckOptions(
|
|
|
155
155
|
violations = rule.check(options)
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
+
### Excluding Files With `.archignore`
|
|
159
|
+
|
|
160
|
+
Add a `.archignore` file to your project root to permanently exclude generated or
|
|
161
|
+
irrelevant files from architecture checks and file-based metrics:
|
|
162
|
+
|
|
163
|
+
```gitignore
|
|
164
|
+
# Generated code
|
|
165
|
+
generated/
|
|
166
|
+
|
|
167
|
+
# Migration scripts
|
|
168
|
+
migrations/*.py
|
|
169
|
+
|
|
170
|
+
# A single root-level file
|
|
171
|
+
/legacy_adapter.py
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Patterns support comments, blank lines, glob syntax, root-relative paths, path
|
|
175
|
+
patterns, and directory patterns with a trailing `/`.
|
|
158
176
|
### Explaining Rules With `.because(...)`
|
|
159
177
|
|
|
160
178
|
Attach a rationale to a rule so failing assertions explain why the rule exists:
|
|
@@ -417,7 +435,7 @@ def test_no_forbidden_dependency():
|
|
|
417
435
|
|
|
418
436
|
Generate dependency graph reports in multiple formats and narrow them to the part of the codebase you want to inspect.
|
|
419
437
|
|
|
420
|
-
**Using `requests` library repo for example**
|
|
438
|
+
**Using [`requests`](https://github.com/psf/requests) library repo for example**
|
|
421
439
|
|
|
422
440
|
```python
|
|
423
441
|
from archunitpython import project_graph
|
|
@@ -430,7 +448,7 @@ def test_export_dependency_graph_reports():
|
|
|
430
448
|
if __name__ == "__main__":
|
|
431
449
|
test_export_dependency_graph_reports()
|
|
432
450
|
```
|
|
433
|
-
**
|
|
451
|
+
**Exported mermaid diagram**
|
|
434
452
|
``` mermaid
|
|
435
453
|
flowchart LR
|
|
436
454
|
n0["__init__.py"]
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "archunitpython"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.4.0"
|
|
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"
|
|
@@ -17,7 +17,7 @@ def read_project_version() -> str:
|
|
|
17
17
|
content = PYPROJECT.read_text(encoding="utf-8")
|
|
18
18
|
match = re.search(r'^version = "([^"]+)"$', content, re.MULTILINE)
|
|
19
19
|
if match is None:
|
|
20
|
-
raise RuntimeError("Could not find project.version in pyproject.toml")
|
|
20
|
+
raise RuntimeError("Could not find [project].version in pyproject.toml")
|
|
21
21
|
return match.group(1)
|
|
22
22
|
|
|
23
23
|
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/extraction/extract_graph.py
RENAMED
|
@@ -29,6 +29,8 @@ _DEFAULT_EXCLUDE = [
|
|
|
29
29
|
"*.egg-info",
|
|
30
30
|
]
|
|
31
31
|
|
|
32
|
+
_ARCHIGNORE_FILE = ".archignore"
|
|
33
|
+
|
|
32
34
|
_IGNORE_DIRECTIVE_REGEX = re.compile(
|
|
33
35
|
r"#\s*archunit(?::|-)\s*ignore"
|
|
34
36
|
r"(?:\([^)]*\))?"
|
|
@@ -88,9 +90,7 @@ def extract_graph(
|
|
|
88
90
|
project_path = os.getcwd()
|
|
89
91
|
|
|
90
92
|
project_path = os.path.abspath(project_path)
|
|
91
|
-
excludes = (
|
|
92
|
-
list(set(exclude_patterns)) if exclude_patterns is not None else list(_DEFAULT_EXCLUDE)
|
|
93
|
-
)
|
|
93
|
+
excludes = _resolve_exclude_patterns(project_path, exclude_patterns)
|
|
94
94
|
ignore_type_checking_imports = bool(options and options.ignore_type_checking_imports)
|
|
95
95
|
cache_key = _build_cache_key(project_path, excludes, ignore_type_checking_imports)
|
|
96
96
|
|
|
@@ -122,6 +122,34 @@ def _build_cache_key(
|
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
|
|
125
|
+
def _resolve_exclude_patterns(
|
|
126
|
+
project_path: str,
|
|
127
|
+
exclude_patterns: list[str] | None,
|
|
128
|
+
) -> list[str]:
|
|
129
|
+
"""Resolve exclude patterns (explicit or defaults) plus any .archignore patterns."""
|
|
130
|
+
excludes = list(exclude_patterns) if exclude_patterns is not None else list(_DEFAULT_EXCLUDE)
|
|
131
|
+
excludes.extend(_load_archignore_patterns(project_path))
|
|
132
|
+
return excludes
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _load_archignore_patterns(project_path: str) -> list[str]:
|
|
136
|
+
"""Load .archignore patterns from a project root, if present."""
|
|
137
|
+
archignore_path = os.path.join(project_path, _ARCHIGNORE_FILE)
|
|
138
|
+
try:
|
|
139
|
+
with open(archignore_path, "r", encoding="utf-8", errors="replace") as f:
|
|
140
|
+
lines = f.readlines()
|
|
141
|
+
except OSError:
|
|
142
|
+
return []
|
|
143
|
+
|
|
144
|
+
patterns: list[str] = []
|
|
145
|
+
for line in lines:
|
|
146
|
+
pattern = line.strip()
|
|
147
|
+
if not pattern or pattern.startswith("#"):
|
|
148
|
+
continue
|
|
149
|
+
patterns.append(pattern)
|
|
150
|
+
return patterns
|
|
151
|
+
|
|
152
|
+
|
|
125
153
|
def _extract_graph_uncached(
|
|
126
154
|
project_path: str,
|
|
127
155
|
exclude_patterns: list[str],
|
|
@@ -160,7 +188,7 @@ def _extract_graph_uncached(
|
|
|
160
188
|
if resolved and resolved != _normalize(file_path):
|
|
161
189
|
# Check if the resolved path is in our project
|
|
162
190
|
if not is_external and resolved not in normalized_py_file_set:
|
|
163
|
-
|
|
191
|
+
continue
|
|
164
192
|
|
|
165
193
|
edges.append(
|
|
166
194
|
Edge(
|
|
@@ -182,25 +210,65 @@ def _normalize(path: str) -> str:
|
|
|
182
210
|
def _find_python_files(root: str, exclude: list[str]) -> list[str]:
|
|
183
211
|
"""Recursively find all .py files, excluding specified patterns."""
|
|
184
212
|
py_files: list[str] = []
|
|
213
|
+
root = os.path.abspath(root)
|
|
185
214
|
for dirpath, dirnames, filenames in os.walk(root):
|
|
186
215
|
# Filter out excluded directories in-place
|
|
187
|
-
dirnames[:] = [
|
|
216
|
+
dirnames[:] = [
|
|
217
|
+
d
|
|
218
|
+
for d in dirnames
|
|
219
|
+
if not _should_exclude_path(os.path.join(dirpath, d), root, exclude, is_dir=True)
|
|
220
|
+
]
|
|
188
221
|
|
|
189
222
|
for filename in filenames:
|
|
190
|
-
|
|
191
|
-
|
|
223
|
+
full_path = os.path.join(dirpath, filename)
|
|
224
|
+
if filename.endswith(".py") and not _should_exclude_path(
|
|
225
|
+
full_path, root, exclude, is_dir=False
|
|
226
|
+
):
|
|
192
227
|
py_files.append(os.path.abspath(full_path))
|
|
193
228
|
|
|
194
229
|
return py_files
|
|
195
230
|
|
|
196
231
|
|
|
197
|
-
def
|
|
198
|
-
|
|
232
|
+
def _should_exclude_path(
|
|
233
|
+
path: str,
|
|
234
|
+
root: str,
|
|
235
|
+
patterns: list[str],
|
|
236
|
+
*,
|
|
237
|
+
is_dir: bool,
|
|
238
|
+
) -> bool:
|
|
239
|
+
"""Check if a path matches any exclude pattern."""
|
|
199
240
|
import fnmatch
|
|
200
241
|
|
|
201
|
-
|
|
202
|
-
|
|
242
|
+
rel_path = _normalize(os.path.relpath(path, root))
|
|
243
|
+
name = os.path.basename(path)
|
|
244
|
+
|
|
245
|
+
for raw_pattern in patterns:
|
|
246
|
+
pattern = raw_pattern.strip().replace("\\", "/")
|
|
247
|
+
if not pattern or pattern.startswith("#"):
|
|
248
|
+
continue
|
|
249
|
+
|
|
250
|
+
pattern = pattern.removeprefix("./")
|
|
251
|
+
anchored = pattern.startswith("/")
|
|
252
|
+
if anchored:
|
|
253
|
+
pattern = pattern[1:]
|
|
254
|
+
|
|
255
|
+
dir_only = pattern.endswith("/")
|
|
256
|
+
if dir_only:
|
|
257
|
+
pattern = pattern.rstrip("/")
|
|
258
|
+
if not is_dir:
|
|
259
|
+
continue
|
|
260
|
+
|
|
261
|
+
if not pattern:
|
|
262
|
+
continue
|
|
263
|
+
|
|
264
|
+
if "/" in pattern or anchored:
|
|
265
|
+
if fnmatch.fnmatch(rel_path, pattern):
|
|
266
|
+
return True
|
|
267
|
+
if is_dir and rel_path == pattern:
|
|
268
|
+
return True
|
|
269
|
+
elif fnmatch.fnmatch(name, pattern):
|
|
203
270
|
return True
|
|
271
|
+
|
|
204
272
|
return False
|
|
205
273
|
|
|
206
274
|
|
|
@@ -5,7 +5,10 @@ from __future__ import annotations
|
|
|
5
5
|
import ast
|
|
6
6
|
import os
|
|
7
7
|
|
|
8
|
-
from archunitpython.common.extraction.extract_graph import
|
|
8
|
+
from archunitpython.common.extraction.extract_graph import (
|
|
9
|
+
_find_python_files,
|
|
10
|
+
_resolve_exclude_patterns,
|
|
11
|
+
)
|
|
9
12
|
from archunitpython.metrics.common.types import (
|
|
10
13
|
ClassInfo,
|
|
11
14
|
EnhancedClassInfo,
|
|
@@ -33,7 +36,7 @@ def extract_class_info(
|
|
|
33
36
|
project_path = os.getcwd()
|
|
34
37
|
|
|
35
38
|
project_path = os.path.abspath(project_path)
|
|
36
|
-
excludes =
|
|
39
|
+
excludes = _resolve_exclude_patterns(project_path, exclude_patterns)
|
|
37
40
|
py_files = _find_python_files(project_path, excludes)
|
|
38
41
|
|
|
39
42
|
classes: list[ClassInfo] = []
|
|
@@ -53,7 +56,7 @@ def extract_enhanced_class_info(
|
|
|
53
56
|
project_path = os.getcwd()
|
|
54
57
|
|
|
55
58
|
project_path = os.path.abspath(project_path)
|
|
56
|
-
excludes =
|
|
59
|
+
excludes = _resolve_exclude_patterns(project_path, exclude_patterns)
|
|
57
60
|
py_files = _find_python_files(project_path, excludes)
|
|
58
61
|
|
|
59
62
|
results: list[FileAnalysisResult] = []
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/fluentapi/metrics.py
RENAMED
|
@@ -251,13 +251,13 @@ class FileMetricCondition(RuleRationaleMixin):
|
|
|
251
251
|
import os
|
|
252
252
|
|
|
253
253
|
from archunitpython.common.extraction.extract_graph import (
|
|
254
|
-
_DEFAULT_EXCLUDE,
|
|
255
254
|
_find_python_files,
|
|
255
|
+
_resolve_exclude_patterns,
|
|
256
256
|
)
|
|
257
257
|
|
|
258
258
|
project = self._project_path or os.getcwd()
|
|
259
259
|
project = os.path.abspath(project)
|
|
260
|
-
files = _find_python_files(project,
|
|
260
|
+
files = _find_python_files(project, _resolve_exclude_patterns(project, None))
|
|
261
261
|
violations: list[Violation] = []
|
|
262
262
|
|
|
263
263
|
for file_path in files:
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"""Tests for declaration detection utilities."""
|
|
2
2
|
|
|
3
|
+
import ast
|
|
4
|
+
|
|
3
5
|
from archunitpython.common.util.declaration_detector import (
|
|
4
|
-
DeclarationCounts,
|
|
5
6
|
count_declarations,
|
|
6
7
|
is_abstract_class,
|
|
7
8
|
is_abstract_method,
|
|
8
9
|
is_protocol_class,
|
|
9
10
|
)
|
|
10
|
-
import ast
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class TestIsAbstractClass:
|
|
@@ -11,6 +11,7 @@ from archunitpython.common.extraction.extract_graph import (
|
|
|
11
11
|
_extract_imports,
|
|
12
12
|
_find_python_files,
|
|
13
13
|
_normalize,
|
|
14
|
+
_resolve_exclude_patterns,
|
|
14
15
|
clear_graph_cache,
|
|
15
16
|
extract_graph,
|
|
16
17
|
)
|
|
@@ -164,6 +165,73 @@ class TestExtractGraph:
|
|
|
164
165
|
assert len(edges_with_kinds) > 0
|
|
165
166
|
|
|
166
167
|
|
|
168
|
+
class TestArchignore:
|
|
169
|
+
def setup_method(self):
|
|
170
|
+
clear_graph_cache()
|
|
171
|
+
self._temp_dir = Path(__file__).resolve().parent / ".tmp" / f"project_{uuid4().hex}"
|
|
172
|
+
self._temp_dir.mkdir(parents=True)
|
|
173
|
+
|
|
174
|
+
def teardown_method(self):
|
|
175
|
+
shutil.rmtree(self._temp_dir, ignore_errors=True)
|
|
176
|
+
|
|
177
|
+
def _write(self, relative_path: str, content: str = "") -> None:
|
|
178
|
+
path = self._temp_dir / relative_path
|
|
179
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
180
|
+
path.write_text(content, encoding="utf-8")
|
|
181
|
+
|
|
182
|
+
def test_archignore_excludes_files_and_directories(self):
|
|
183
|
+
self._write(
|
|
184
|
+
".archignore",
|
|
185
|
+
"\n".join(
|
|
186
|
+
[
|
|
187
|
+
"# Ignore generated architecture-test inputs",
|
|
188
|
+
"ignored.py",
|
|
189
|
+
"generated/",
|
|
190
|
+
"nested/*.py",
|
|
191
|
+
"/root_ignored.py",
|
|
192
|
+
]
|
|
193
|
+
),
|
|
194
|
+
)
|
|
195
|
+
self._write("keep.py")
|
|
196
|
+
self._write("ignored.py")
|
|
197
|
+
self._write("root_ignored.py")
|
|
198
|
+
self._write("generated/generated.py")
|
|
199
|
+
self._write("nested/ignored_nested.py")
|
|
200
|
+
|
|
201
|
+
excludes = _resolve_exclude_patterns(str(self._temp_dir), ["__pycache__"])
|
|
202
|
+
files = _find_python_files(str(self._temp_dir), excludes)
|
|
203
|
+
relative_files = {
|
|
204
|
+
Path(file_path).relative_to(self._temp_dir).as_posix()
|
|
205
|
+
for file_path in files
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
assert relative_files == {"keep.py"}
|
|
209
|
+
|
|
210
|
+
def test_archignore_ignored_files_are_not_dependency_targets(self):
|
|
211
|
+
self._write(".archignore", "ignored.py\n")
|
|
212
|
+
self._write("keep.py", "import ignored\n")
|
|
213
|
+
self._write("ignored.py", "VALUE = 1\n")
|
|
214
|
+
|
|
215
|
+
graph = extract_graph(str(self._temp_dir))
|
|
216
|
+
targets = {edge.target for edge in graph}
|
|
217
|
+
|
|
218
|
+
ignored_path = _normalize(str((self._temp_dir / "ignored.py").resolve()))
|
|
219
|
+
assert ignored_path not in targets
|
|
220
|
+
|
|
221
|
+
def test_archignore_with_invalid_utf8_bytes_does_not_abort_extraction(self):
|
|
222
|
+
(self._temp_dir / ".archignore").write_bytes(b"ignored.py\n\xff\n")
|
|
223
|
+
self._write("keep.py")
|
|
224
|
+
self._write("ignored.py")
|
|
225
|
+
|
|
226
|
+
graph = extract_graph(str(self._temp_dir))
|
|
227
|
+
sources = {edge.source for edge in graph}
|
|
228
|
+
|
|
229
|
+
keep_path = _normalize(str((self._temp_dir / "keep.py").resolve()))
|
|
230
|
+
ignored_path = _normalize(str((self._temp_dir / "ignored.py").resolve()))
|
|
231
|
+
assert keep_path in sources
|
|
232
|
+
assert ignored_path not in sources
|
|
233
|
+
|
|
234
|
+
|
|
167
235
|
class TestTypeCheckingImportHandling:
|
|
168
236
|
def setup_method(self):
|
|
169
237
|
clear_graph_cache()
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
-
from archunitpython.common.extraction.graph import Edge
|
|
6
5
|
from archunitpython.common.projection.types import ProjectedEdge, ProjectedNode
|
|
7
6
|
from archunitpython.common.regex_factory import RegexFactory
|
|
8
7
|
from archunitpython.files.assertion.custom_file_logic import (
|
|
9
8
|
CustomFileViolation,
|
|
10
|
-
FileInfo,
|
|
11
9
|
_build_file_info,
|
|
12
10
|
gather_custom_file_violations,
|
|
13
11
|
)
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/utils/helpers.py
RENAMED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"""Sample utilities - imports external modules only."""
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
3
|
import json
|
|
4
|
+
import os
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def read_config(path: str) -> Any:
|
|
9
9
|
with open(path) as f:
|
|
10
10
|
return json.load(f)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def platform_name() -> str:
|
|
14
|
+
return os.name
|
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
-
from archunitpython.metrics.
|
|
6
|
-
from archunitpython.metrics.extraction.extract_class_info import (
|
|
7
|
-
extract_class_info,
|
|
8
|
-
extract_enhanced_class_info,
|
|
9
|
-
)
|
|
5
|
+
from archunitpython.metrics.assertion.metric_thresholds import check_threshold
|
|
10
6
|
from archunitpython.metrics.calculation.count import (
|
|
11
7
|
ClassCountMetric,
|
|
12
8
|
FieldCountMetric,
|
|
@@ -16,6 +12,9 @@ from archunitpython.metrics.calculation.count import (
|
|
|
16
12
|
MethodCountMetric,
|
|
17
13
|
StatementCountMetric,
|
|
18
14
|
)
|
|
15
|
+
from archunitpython.metrics.calculation.distance import (
|
|
16
|
+
calculate_distance_metrics_for_project,
|
|
17
|
+
)
|
|
19
18
|
from archunitpython.metrics.calculation.lcom import (
|
|
20
19
|
LCOM1,
|
|
21
20
|
LCOM2,
|
|
@@ -26,11 +25,11 @@ from archunitpython.metrics.calculation.lcom import (
|
|
|
26
25
|
LCOM96b,
|
|
27
26
|
LCOMStar,
|
|
28
27
|
)
|
|
29
|
-
from archunitpython.metrics.
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
from archunitpython.metrics.common.types import ClassInfo, FieldInfo, MethodInfo
|
|
29
|
+
from archunitpython.metrics.extraction.extract_class_info import (
|
|
30
|
+
extract_class_info,
|
|
31
|
+
extract_enhanced_class_info,
|
|
32
32
|
)
|
|
33
|
-
from archunitpython.metrics.assertion.metric_thresholds import check_threshold
|
|
34
33
|
|
|
35
34
|
FIXTURES_DIR = os.path.join(
|
|
36
35
|
os.path.dirname(os.path.dirname(__file__)), "fixtures", "metrics_project"
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"""Tests for the metrics fluent API."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from uuid import uuid4
|
|
4
7
|
|
|
5
8
|
from archunitpython.metrics.assertion.metric_thresholds import (
|
|
6
9
|
FileCountViolation,
|
|
@@ -40,6 +43,29 @@ class TestCountMetricsFluentAPI:
|
|
|
40
43
|
assert len(file_violations) > 0
|
|
41
44
|
|
|
42
45
|
|
|
46
|
+
class TestMetricsArchignore:
|
|
47
|
+
def setup_method(self):
|
|
48
|
+
self._temp_dir = Path(__file__).resolve().parent / ".tmp" / f"project_{uuid4().hex}"
|
|
49
|
+
self._temp_dir.mkdir(parents=True)
|
|
50
|
+
|
|
51
|
+
def teardown_method(self):
|
|
52
|
+
shutil.rmtree(self._temp_dir, ignore_errors=True)
|
|
53
|
+
|
|
54
|
+
def test_file_metrics_respect_archignore(self):
|
|
55
|
+
(self._temp_dir / ".archignore").write_text("ignored.py\n", encoding="utf-8")
|
|
56
|
+
(self._temp_dir / "keep.py").write_text("VALUE = 1\n", encoding="utf-8")
|
|
57
|
+
(self._temp_dir / "ignored.py").write_text(
|
|
58
|
+
"\n".join(f"VALUE_{i} = {i}" for i in range(20)),
|
|
59
|
+
encoding="utf-8",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
violations = (
|
|
63
|
+
metrics(str(self._temp_dir)).count().lines_of_code().should_be_below(5).check()
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
assert violations == []
|
|
67
|
+
|
|
68
|
+
|
|
43
69
|
class TestLCOMMetricsFluentAPI:
|
|
44
70
|
def test_lcom96b_below(self):
|
|
45
71
|
violations = metrics(FIXTURES_DIR).lcom().lcom96b().should_be_below(1.0).check()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/assertion/__init__.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/assertion/violation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/extraction/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/fluentapi/__init__.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/fluentapi/checkable.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/cycles/cycles.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/cycles/model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/project_cycles.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/project_edges.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/projection/project_nodes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/common/util/declaration_detector.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/cycle_free.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/depend_on_files.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/assertion/matching_files.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/files/fluentapi/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/layers/assertion/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/layers/fluentapi/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/assertion/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/calculation/__init__.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/calculation/count.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/calculation/distance.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/calculation/lcom.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/extraction/__init__.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/fluentapi/__init__.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/fluentapi/export_utils.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/metrics/projection/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/assertion/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/fluentapi/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/projection/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/uml/export_diagram.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/slices/uml/generate_rules.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/common/color_utils.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/common/violation_factory.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/src/archunitpython/testing/pytest_plugin/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/architecture.puml
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/controllers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/models/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/services/__init__.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/services/service.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/services/service_a.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/services/service_b.py
RENAMED
|
File without changes
|
{archunitpython-1.3.0 → archunitpython-1.4.0}/tests/fixtures/sample_project/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|