archunitpython 1.2.0__tar.gz → 1.2.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.
- {archunitpython-1.2.0 → archunitpython-1.2.1}/CHANGELOG.md +18 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/PKG-INFO +5 -7
- {archunitpython-1.2.0 → archunitpython-1.2.1}/README.md +4 -6
- {archunitpython-1.2.0 → archunitpython-1.2.1}/pyproject.toml +1 -1
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/__init__.py +1 -1
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/extraction/extract_graph.py +8 -22
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/pattern_matching.py +1 -3
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/cycles/johnsons_apsp.py +4 -9
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/cycles/tarjan_scc.py +2 -6
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/project_cycles.py +1 -2
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/util/logger.py +1 -3
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/assertion/custom_file_logic.py +3 -9
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/assertion/depend_on_external_modules.py +3 -8
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/assertion/depend_on_files.py +4 -12
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/fluentapi/files.py +9 -27
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/assertion/metric_thresholds.py +1 -3
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/calculation/distance.py +1 -3
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/extraction/extract_class_info.py +3 -9
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/fluentapi/export_utils.py +2 -6
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/fluentapi/metrics.py +12 -38
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/fluentapi/slices.py +4 -12
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/uml/generate_rules.py +2 -6
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/testing/common/violation_factory.py +1 -3
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/common/test_extract_graph.py +5 -19
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/files/test_files_fluentapi.py +17 -70
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/metrics_project/service.py +1 -2
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/integration/test_e2e.py +5 -6
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/metrics/test_export.py +2 -6
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/metrics/test_metrics.py +5 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/metrics/test_metrics_fluentapi.py +53 -31
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/slices/test_slices.py +36 -9
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.editorconfig +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.gitattributes +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/CODEOWNERS +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/FUNDING.yml +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/PAGES.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/dependabot.yml +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/pull_request_template.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/workflows/docs.yaml +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/workflows/integrate.yaml +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.github/workflows/stale.yaml +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.gitignore +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/.releaserc.json +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/BACKLOG.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/CONTRIBUTING.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/LICENSE +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/assets/logo-rounded.png +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/research/product-direction/architecture-testing-landscape.md +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/scripts/bump_release_version.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/scripts/check_release_metadata.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/assertion/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/assertion/violation.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/error/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/error/errors.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/extraction/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/extraction/graph.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/fluentapi/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/fluentapi/checkable.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/logging/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/logging/types.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/cycles/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/cycles/cycle_utils.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/cycles/cycles.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/cycles/model.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/edge_projections.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/project_edges.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/project_nodes.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/projection/types.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/regex_factory.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/types.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/util/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/util/declaration_detector.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/assertion/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/assertion/cycle_free.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/assertion/matching_files.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/fluentapi/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/graph/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/graph/graph_reporter.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/layers/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/layers/assertion/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/layers/assertion/layer_dependencies.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/layers/fluentapi/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/layers/fluentapi/layers.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/assertion/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/calculation/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/calculation/count.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/calculation/lcom.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/common/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/common/types.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/extraction/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/fluentapi/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/projection/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/py.typed +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/assertion/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/assertion/admissible_edges.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/fluentapi/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/projection/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/projection/slicing_projections.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/uml/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/slices/uml/export_diagram.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/testing/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/testing/assertion.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/testing/common/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/testing/common/color_utils.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/testing/pytest_plugin/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/common/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/common/test_core_types.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/common/test_cycles.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/common/test_declaration_detector.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/common/test_logger.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/common/test_pattern_matching.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/common/test_projection.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/files/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/files/test_file_assertions.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/architecture.puml +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/controllers/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/controllers/controller.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/models/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/models/model.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/services/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/services/service.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/services/service_a.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/services/service_b.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/utils/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/fixtures/sample_project/utils/helpers.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/graph/test_graph_reporter.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/integration/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/layers/test_layers.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/metrics/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/slices/__init__.py +0 -0
- {archunitpython-1.2.0 → archunitpython-1.2.1}/tests/test_setup.py +0 -0
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## [1.2.1](https://github.com/LukasNiessen/ArchUnitPython/compare/v1.2.0...v1.2.1) (2026-06-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **extract_graph:** validate AST line number before range lookup ([84c9ef4](https://github.com/LukasNiessen/ArchUnitPython/commit/84c9ef4a97333ed1fa302778725ab6d5ba891574))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Performance Improvements
|
|
10
|
+
|
|
11
|
+
* **extract_graph:** optimize file path normalization ([14b4a95](https://github.com/LukasNiessen/ArchUnitPython/commit/14b4a955576d4ee2464c8c2cceb71f28b9135198))
|
|
12
|
+
* **extract_graph:** replace linear search in `_in_type_checking()` with binary search ([1285b5e](https://github.com/LukasNiessen/ArchUnitPython/commit/1285b5e5ac513d7897d42b5e6c1fcb0bd83c1835))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Reverts
|
|
16
|
+
|
|
17
|
+
* Reverted the binary search implementation in `_in_type_checking()` function. ([d06a455](https://github.com/LukasNiessen/ArchUnitPython/commit/d06a45569fdfe5eab5e6825f6046c773b66d61c7))
|
|
18
|
+
|
|
1
19
|
# [1.2.0](https://github.com/LukasNiessen/ArchUnitPython/compare/v1.1.2...v1.2.0) (2026-06-27)
|
|
2
20
|
|
|
3
21
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: archunitpython
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.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
|
|
@@ -39,11 +39,9 @@ Description-Content-Type: text/markdown
|
|
|
39
39
|
<!-- spacer -->
|
|
40
40
|
<p></p>
|
|
41
41
|
|
|
42
|
-
[](https://opensource.org/licenses/MIT)
|
|
43
|
-
[](https://pepy.tech/project/archunitpython)
|
|
46
|
-
[](https://github.com/LukasNiessen/ArchUnitPython)
|
|
42
|
+
[](https://opensource.org/licenses/MIT) [](https://github.com/LukasNiessen/ArchUnitPython/actions/workflows/integrate.yaml) [](https://github.com/LukasNiessen/ArchUnitPython)<br>
|
|
43
|
+
[](https://pepy.tech/project/archunitpython) [](https://pepy.tech/project/archunitpython)
|
|
44
|
+
<!-- [](https://pypi.org/project/archunitpython/) -->
|
|
47
45
|
|
|
48
46
|
</div>
|
|
49
47
|
|
|
@@ -53,7 +51,7 @@ The #1 ArchUnit-style architecture testing library for Python, measured by GitHu
|
|
|
53
51
|
|
|
54
52
|
_Inspired by the amazing ArchUnit library but we are not affiliated with ArchUnit._
|
|
55
53
|
|
|
56
|
-
[Setup](#-setup) • [Use Cases](#-use-cases) • [Features](#-features) • [Why ArchUnitPython?](#-library-comparison) • [Contributing](CONTRIBUTING.md)
|
|
54
|
+
[Setup](#-setup) • [Use Cases](#-use-cases) • [Features](#-features) • [Why ArchUnitPython?](#-library-comparison) • [Sponsor](https://github.com/sponsors/LukasNiessen) • [Contributing](CONTRIBUTING.md)
|
|
57
55
|
|
|
58
56
|
## ⚡ 5 min Quickstart
|
|
59
57
|
|
|
@@ -6,11 +6,9 @@
|
|
|
6
6
|
<!-- spacer -->
|
|
7
7
|
<p></p>
|
|
8
8
|
|
|
9
|
-
[](https://opensource.org/licenses/MIT)
|
|
10
|
-
[](https://pepy.tech/project/archunitpython)
|
|
13
|
-
[](https://github.com/LukasNiessen/ArchUnitPython)
|
|
9
|
+
[](https://opensource.org/licenses/MIT) [](https://github.com/LukasNiessen/ArchUnitPython/actions/workflows/integrate.yaml) [](https://github.com/LukasNiessen/ArchUnitPython)<br>
|
|
10
|
+
[](https://pepy.tech/project/archunitpython) [](https://pepy.tech/project/archunitpython)
|
|
11
|
+
<!-- [](https://pypi.org/project/archunitpython/) -->
|
|
14
12
|
|
|
15
13
|
</div>
|
|
16
14
|
|
|
@@ -20,7 +18,7 @@ The #1 ArchUnit-style architecture testing library for Python, measured by GitHu
|
|
|
20
18
|
|
|
21
19
|
_Inspired by the amazing ArchUnit library but we are not affiliated with ArchUnit._
|
|
22
20
|
|
|
23
|
-
[Setup](#-setup) • [Use Cases](#-use-cases) • [Features](#-features) • [Why ArchUnitPython?](#-library-comparison) • [Contributing](CONTRIBUTING.md)
|
|
21
|
+
[Setup](#-setup) • [Use Cases](#-use-cases) • [Features](#-features) • [Why ArchUnitPython?](#-library-comparison) • [Sponsor](https://github.com/sponsors/LukasNiessen) • [Contributing](CONTRIBUTING.md)
|
|
24
22
|
|
|
25
23
|
## ⚡ 5 min Quickstart
|
|
26
24
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "archunitpython"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.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"
|
{archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/common/extraction/extract_graph.py
RENAMED
|
@@ -91,12 +91,8 @@ def extract_graph(
|
|
|
91
91
|
excludes = (
|
|
92
92
|
list(set(exclude_patterns)) if exclude_patterns is not None else list(_DEFAULT_EXCLUDE)
|
|
93
93
|
)
|
|
94
|
-
ignore_type_checking_imports = bool(
|
|
95
|
-
|
|
96
|
-
)
|
|
97
|
-
cache_key = _build_cache_key(
|
|
98
|
-
project_path, excludes, ignore_type_checking_imports
|
|
99
|
-
)
|
|
94
|
+
ignore_type_checking_imports = bool(options and options.ignore_type_checking_imports)
|
|
95
|
+
cache_key = _build_cache_key(project_path, excludes, ignore_type_checking_imports)
|
|
100
96
|
|
|
101
97
|
if options and options.clear_cache:
|
|
102
98
|
_graph_cache.pop(cache_key, None)
|
|
@@ -137,6 +133,7 @@ def _extract_graph_uncached(
|
|
|
137
133
|
|
|
138
134
|
edges: list[Edge] = []
|
|
139
135
|
py_files_set = set(py_files)
|
|
136
|
+
normalized_py_file_set = {_normalize(f) for f in py_files_set}
|
|
140
137
|
|
|
141
138
|
for file_path in py_files:
|
|
142
139
|
# Add self-referencing edge (ensures the file appears as a node)
|
|
@@ -148,7 +145,6 @@ def _extract_graph_uncached(
|
|
|
148
145
|
)
|
|
149
146
|
)
|
|
150
147
|
|
|
151
|
-
# Extract and resolve imports
|
|
152
148
|
imports = _extract_located_imports(file_path)
|
|
153
149
|
for located_import in imports:
|
|
154
150
|
module_name = located_import.module_name
|
|
@@ -163,9 +159,7 @@ def _extract_graph_uncached(
|
|
|
163
159
|
)
|
|
164
160
|
if resolved and resolved != _normalize(file_path):
|
|
165
161
|
# Check if the resolved path is in our project
|
|
166
|
-
if not is_external and resolved not in
|
|
167
|
-
_normalize(f) for f in py_files_set
|
|
168
|
-
}:
|
|
162
|
+
if not is_external and resolved not in normalized_py_file_set:
|
|
169
163
|
is_external = True
|
|
170
164
|
|
|
171
165
|
edges.append(
|
|
@@ -190,11 +184,7 @@ def _find_python_files(root: str, exclude: list[str]) -> list[str]:
|
|
|
190
184
|
py_files: list[str] = []
|
|
191
185
|
for dirpath, dirnames, filenames in os.walk(root):
|
|
192
186
|
# Filter out excluded directories in-place
|
|
193
|
-
dirnames[:] = [
|
|
194
|
-
d
|
|
195
|
-
for d in dirnames
|
|
196
|
-
if not _should_exclude(d, exclude)
|
|
197
|
-
]
|
|
187
|
+
dirnames[:] = [d for d in dirnames if not _should_exclude(d, exclude)]
|
|
198
188
|
|
|
199
189
|
for filename in filenames:
|
|
200
190
|
if filename.endswith(".py") and not _should_exclude(filename, exclude):
|
|
@@ -349,18 +339,14 @@ def _find_type_checking_ranges(tree: ast.Module) -> list[tuple[int, int]]:
|
|
|
349
339
|
if is_type_checking and node.body:
|
|
350
340
|
start = node.body[0].lineno
|
|
351
341
|
end = max(
|
|
352
|
-
getattr(n, "end_lineno", n.lineno)
|
|
353
|
-
for n in node.body
|
|
354
|
-
if hasattr(n, "lineno")
|
|
342
|
+
getattr(n, "end_lineno", n.lineno) for n in node.body if hasattr(n, "lineno")
|
|
355
343
|
)
|
|
356
344
|
ranges.append((start, end))
|
|
357
345
|
|
|
358
|
-
return ranges
|
|
346
|
+
return sorted(ranges, key=lambda ele: ele[0])
|
|
359
347
|
|
|
360
348
|
|
|
361
|
-
def _in_type_checking(
|
|
362
|
-
node: ast.AST, ranges: list[tuple[int, int]]
|
|
363
|
-
) -> bool:
|
|
349
|
+
def _in_type_checking(node: ast.AST, ranges: list[tuple[int, int]]) -> bool:
|
|
364
350
|
"""Check if a node is inside a TYPE_CHECKING block."""
|
|
365
351
|
if not hasattr(node, "lineno"):
|
|
366
352
|
return False
|
|
@@ -50,9 +50,7 @@ def matches_pattern(file_path: str, filter_: Filter) -> bool:
|
|
|
50
50
|
return bool(filter_.regexp.search(target_string))
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
def matches_pattern_classname(
|
|
54
|
-
class_name: str, file_path: str, filter_: Filter
|
|
55
|
-
) -> bool:
|
|
53
|
+
def matches_pattern_classname(class_name: str, file_path: str, filter_: Filter) -> bool:
|
|
56
54
|
"""Check if a class/file matches a filter, supporting classname target."""
|
|
57
55
|
target = filter_.options.target
|
|
58
56
|
|
|
@@ -53,13 +53,9 @@ class JohnsonsAPSP:
|
|
|
53
53
|
if self._is_part_of_current_start_cycle(current_node):
|
|
54
54
|
self._unblock(current_node)
|
|
55
55
|
else:
|
|
56
|
-
for neighbour in CycleUtils.get_outgoing_neighbours(
|
|
57
|
-
current_node, self._graph
|
|
58
|
-
):
|
|
56
|
+
for neighbour in CycleUtils.get_outgoing_neighbours(current_node, self._graph):
|
|
59
57
|
if self._is_blocked(neighbour):
|
|
60
|
-
self._blocked_map.append(
|
|
61
|
-
_BlockedBy(blocked=current_node, by=neighbour)
|
|
62
|
-
)
|
|
58
|
+
self._blocked_map.append(_BlockedBy(blocked=current_node, by=neighbour))
|
|
63
59
|
|
|
64
60
|
def _unblock(self, node: NumberNode) -> None:
|
|
65
61
|
self._blocked = [n for n in self._blocked if n is not node]
|
|
@@ -74,9 +70,8 @@ class JohnsonsAPSP:
|
|
|
74
70
|
if self._start is None:
|
|
75
71
|
return False
|
|
76
72
|
for cycle in self._cycles:
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
and any(e.from_node == current_node.node for e in cycle)
|
|
73
|
+
if cycle[0].from_node == self._start.node and any(
|
|
74
|
+
e.from_node == current_node.node for e in cycle
|
|
80
75
|
):
|
|
81
76
|
return True
|
|
82
77
|
return False
|
|
@@ -18,9 +18,7 @@ class _Vertex:
|
|
|
18
18
|
class TarjanSCC:
|
|
19
19
|
"""Tarjan's algorithm for finding strongly connected components."""
|
|
20
20
|
|
|
21
|
-
def find_strongly_connected_components(
|
|
22
|
-
self, edges: list[NumberEdge]
|
|
23
|
-
) -> list[list[NumberEdge]]:
|
|
21
|
+
def find_strongly_connected_components(self, edges: list[NumberEdge]) -> list[list[NumberEdge]]:
|
|
24
22
|
"""Find all strongly connected components in the graph.
|
|
25
23
|
|
|
26
24
|
Returns a list of edge lists, where each inner list contains
|
|
@@ -78,9 +76,7 @@ class TarjanSCC:
|
|
|
78
76
|
if scc_vertices:
|
|
79
77
|
scc_ids = {v.id for v in scc_vertices}
|
|
80
78
|
scc_edges = [
|
|
81
|
-
e
|
|
82
|
-
for e in self._edges
|
|
83
|
-
if e.from_node in scc_ids and e.to_node in scc_ids
|
|
79
|
+
e for e in self._edges if e.from_node in scc_ids and e.to_node in scc_ids
|
|
84
80
|
]
|
|
85
81
|
if scc_edges:
|
|
86
82
|
self._sccs.append(scc_edges)
|
|
@@ -44,9 +44,7 @@ class CheckLogger:
|
|
|
44
44
|
|
|
45
45
|
mode = "a" if options.append_to_log_file else "w"
|
|
46
46
|
self._file_handler = logging.FileHandler(str(log_path), mode=mode)
|
|
47
|
-
self._file_handler.setFormatter(
|
|
48
|
-
logging.Formatter("[%(levelname)s] %(message)s")
|
|
49
|
-
)
|
|
47
|
+
self._file_handler.setFormatter(logging.Formatter("[%(levelname)s] %(message)s"))
|
|
50
48
|
self._logger.addHandler(self._file_handler)
|
|
51
49
|
|
|
52
50
|
def _log(self, level: str, options: LoggingOptions | None, message: str) -> None:
|
|
@@ -83,9 +83,7 @@ def gather_custom_file_violations(
|
|
|
83
83
|
|
|
84
84
|
for node in nodes:
|
|
85
85
|
# Check if node matches all pre-filters
|
|
86
|
-
if pre_filters and not all(
|
|
87
|
-
matches_pattern(node.label, f) for f in pre_filters
|
|
88
|
-
):
|
|
86
|
+
if pre_filters and not all(matches_pattern(node.label, f) for f in pre_filters):
|
|
89
87
|
continue
|
|
90
88
|
|
|
91
89
|
file_info = _build_file_info(node.label)
|
|
@@ -94,14 +92,10 @@ def gather_custom_file_violations(
|
|
|
94
92
|
if is_negated:
|
|
95
93
|
# shouldNot: violation if condition IS True
|
|
96
94
|
if result:
|
|
97
|
-
violations.append(
|
|
98
|
-
CustomFileViolation(message=message, file_info=file_info)
|
|
99
|
-
)
|
|
95
|
+
violations.append(CustomFileViolation(message=message, file_info=file_info))
|
|
100
96
|
else:
|
|
101
97
|
# should: violation if condition is NOT True
|
|
102
98
|
if not result:
|
|
103
|
-
violations.append(
|
|
104
|
-
CustomFileViolation(message=message, file_info=file_info)
|
|
105
|
-
)
|
|
99
|
+
violations.append(CustomFileViolation(message=message, file_info=file_info))
|
|
106
100
|
|
|
107
101
|
return violations
|
|
@@ -34,8 +34,7 @@ def gather_depend_on_external_module_violations(
|
|
|
34
34
|
|
|
35
35
|
for edge in edges:
|
|
36
36
|
source_matches = all(
|
|
37
|
-
matches_pattern(edge.source_label, filter_)
|
|
38
|
-
for filter_ in subject_filters
|
|
37
|
+
matches_pattern(edge.source_label, filter_) for filter_ in subject_filters
|
|
39
38
|
)
|
|
40
39
|
if not source_matches:
|
|
41
40
|
continue
|
|
@@ -49,16 +48,12 @@ def gather_depend_on_external_module_violations(
|
|
|
49
48
|
if is_negated:
|
|
50
49
|
if target_matches:
|
|
51
50
|
violations.append(
|
|
52
|
-
ViolatingExternalModuleDependency(
|
|
53
|
-
dependency=edge, is_negated=True
|
|
54
|
-
)
|
|
51
|
+
ViolatingExternalModuleDependency(dependency=edge, is_negated=True)
|
|
55
52
|
)
|
|
56
53
|
else:
|
|
57
54
|
if not target_matches:
|
|
58
55
|
violations.append(
|
|
59
|
-
ViolatingExternalModuleDependency(
|
|
60
|
-
dependency=edge, is_negated=False
|
|
61
|
-
)
|
|
56
|
+
ViolatingExternalModuleDependency(dependency=edge, is_negated=False)
|
|
62
57
|
)
|
|
63
58
|
|
|
64
59
|
return violations
|
{archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/files/assertion/depend_on_files.py
RENAMED
|
@@ -41,27 +41,19 @@ def gather_depend_on_file_violations(
|
|
|
41
41
|
violations: list[Violation] = []
|
|
42
42
|
|
|
43
43
|
for edge in edges:
|
|
44
|
-
source_matches = all(
|
|
45
|
-
matches_pattern(edge.source_label, f) for f in subject_filters
|
|
46
|
-
)
|
|
44
|
+
source_matches = all(matches_pattern(edge.source_label, f) for f in subject_filters)
|
|
47
45
|
if not source_matches:
|
|
48
46
|
continue
|
|
49
47
|
|
|
50
|
-
target_matches = all(
|
|
51
|
-
matches_pattern(edge.target_label, f) for f in object_filters
|
|
52
|
-
)
|
|
48
|
+
target_matches = all(matches_pattern(edge.target_label, f) for f in object_filters)
|
|
53
49
|
|
|
54
50
|
if is_negated:
|
|
55
51
|
# shouldNot: violation if dependency EXISTS
|
|
56
52
|
if target_matches:
|
|
57
|
-
violations.append(
|
|
58
|
-
ViolatingFileDependency(dependency=edge, is_negated=True)
|
|
59
|
-
)
|
|
53
|
+
violations.append(ViolatingFileDependency(dependency=edge, is_negated=True))
|
|
60
54
|
else:
|
|
61
55
|
# should: violation if dependency does NOT match
|
|
62
56
|
if not target_matches:
|
|
63
|
-
violations.append(
|
|
64
|
-
ViolatingFileDependency(dependency=edge, is_negated=False)
|
|
65
|
-
)
|
|
57
|
+
violations.append(ViolatingFileDependency(dependency=edge, is_negated=False))
|
|
66
58
|
|
|
67
59
|
return violations
|
|
@@ -76,15 +76,11 @@ class FileConditionBuilder:
|
|
|
76
76
|
|
|
77
77
|
def should(self) -> "PositiveMatchPatternFileConditionBuilder":
|
|
78
78
|
"""Begin positive assertion (files SHOULD ...)."""
|
|
79
|
-
return PositiveMatchPatternFileConditionBuilder(
|
|
80
|
-
self._project_path, list(self._filters)
|
|
81
|
-
)
|
|
79
|
+
return PositiveMatchPatternFileConditionBuilder(self._project_path, list(self._filters))
|
|
82
80
|
|
|
83
81
|
def should_not(self) -> "NegatedMatchPatternFileConditionBuilder":
|
|
84
82
|
"""Begin negative assertion (files SHOULD NOT ...)."""
|
|
85
|
-
return NegatedMatchPatternFileConditionBuilder(
|
|
86
|
-
self._project_path, list(self._filters)
|
|
87
|
-
)
|
|
83
|
+
return NegatedMatchPatternFileConditionBuilder(self._project_path, list(self._filters))
|
|
88
84
|
|
|
89
85
|
|
|
90
86
|
class FilesShouldCondition:
|
|
@@ -111,15 +107,11 @@ class FilesShouldCondition:
|
|
|
111
107
|
|
|
112
108
|
def should(self) -> "PositiveMatchPatternFileConditionBuilder":
|
|
113
109
|
"""Begin positive assertion (files SHOULD ...)."""
|
|
114
|
-
return PositiveMatchPatternFileConditionBuilder(
|
|
115
|
-
self._project_path, list(self._filters)
|
|
116
|
-
)
|
|
110
|
+
return PositiveMatchPatternFileConditionBuilder(self._project_path, list(self._filters))
|
|
117
111
|
|
|
118
112
|
def should_not(self) -> "NegatedMatchPatternFileConditionBuilder":
|
|
119
113
|
"""Begin negative assertion (files SHOULD NOT ...)."""
|
|
120
|
-
return NegatedMatchPatternFileConditionBuilder(
|
|
121
|
-
self._project_path, list(self._filters)
|
|
122
|
-
)
|
|
114
|
+
return NegatedMatchPatternFileConditionBuilder(self._project_path, list(self._filters))
|
|
123
115
|
|
|
124
116
|
|
|
125
117
|
class PositiveMatchPatternFileConditionBuilder:
|
|
@@ -135,9 +127,7 @@ class PositiveMatchPatternFileConditionBuilder:
|
|
|
135
127
|
|
|
136
128
|
def depend_on_files(self) -> "DependOnFileConditionBuilder":
|
|
137
129
|
"""Begin dependency assertion - files SHOULD depend on ..."""
|
|
138
|
-
return DependOnFileConditionBuilder(
|
|
139
|
-
self._project_path, self._filters, is_negated=False
|
|
140
|
-
)
|
|
130
|
+
return DependOnFileConditionBuilder(self._project_path, self._filters, is_negated=False)
|
|
141
131
|
|
|
142
132
|
def depend_on_external_modules(
|
|
143
133
|
self,
|
|
@@ -192,9 +182,7 @@ class NegatedMatchPatternFileConditionBuilder:
|
|
|
192
182
|
|
|
193
183
|
def depend_on_files(self) -> "DependOnFileConditionBuilder":
|
|
194
184
|
"""Begin dependency assertion - files SHOULD NOT depend on ..."""
|
|
195
|
-
return DependOnFileConditionBuilder(
|
|
196
|
-
self._project_path, self._filters, is_negated=True
|
|
197
|
-
)
|
|
185
|
+
return DependOnFileConditionBuilder(self._project_path, self._filters, is_negated=True)
|
|
198
186
|
|
|
199
187
|
def depend_on_external_modules(
|
|
200
188
|
self,
|
|
@@ -243,9 +231,7 @@ class NegatedMatchPatternFileConditionBuilder:
|
|
|
243
231
|
class DependOnFileConditionBuilder:
|
|
244
232
|
"""Configure dependency target patterns."""
|
|
245
233
|
|
|
246
|
-
def __init__(
|
|
247
|
-
self, project_path: str | None, filters: list[Filter], is_negated: bool
|
|
248
|
-
) -> None:
|
|
234
|
+
def __init__(self, project_path: str | None, filters: list[Filter], is_negated: bool) -> None:
|
|
249
235
|
self._project_path = project_path
|
|
250
236
|
self._filters = filters
|
|
251
237
|
self._is_negated = is_negated
|
|
@@ -285,9 +271,7 @@ class DependOnFileConditionBuilder:
|
|
|
285
271
|
class DependOnExternalModuleConditionBuilder:
|
|
286
272
|
"""Configure external module dependency target patterns."""
|
|
287
273
|
|
|
288
|
-
def __init__(
|
|
289
|
-
self, project_path: str | None, filters: list[Filter], is_negated: bool
|
|
290
|
-
) -> None:
|
|
274
|
+
def __init__(self, project_path: str | None, filters: list[Filter], is_negated: bool) -> None:
|
|
291
275
|
self._project_path = project_path
|
|
292
276
|
self._filters = filters
|
|
293
277
|
self._is_negated = is_negated
|
|
@@ -447,9 +431,7 @@ class MatchPatternFileCondition:
|
|
|
447
431
|
if empty is not None:
|
|
448
432
|
return empty
|
|
449
433
|
|
|
450
|
-
return gather_regex_matching_violations(
|
|
451
|
-
nodes, self._check_filters, self._is_negated
|
|
452
|
-
)
|
|
434
|
+
return gather_regex_matching_violations(nodes, self._check_filters, self._is_negated)
|
|
453
435
|
|
|
454
436
|
|
|
455
437
|
class CustomFileCheckableCondition:
|
|
@@ -31,9 +31,7 @@ class FileCountViolation(Violation):
|
|
|
31
31
|
comparison: MetricComparison
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def check_threshold(
|
|
35
|
-
value: float, threshold: float, comparison: MetricComparison
|
|
36
|
-
) -> bool:
|
|
34
|
+
def check_threshold(value: float, threshold: float, comparison: MetricComparison) -> bool:
|
|
37
35
|
"""Check if a value violates a threshold.
|
|
38
36
|
|
|
39
37
|
Returns True if the value is a VIOLATION.
|
{archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/calculation/distance.py
RENAMED
|
@@ -103,8 +103,6 @@ def calculate_distance_metrics_for_project(
|
|
|
103
103
|
average_instability=sum(m.instability for m in metrics) / len(metrics),
|
|
104
104
|
average_distance=sum(m.distance for m in metrics) / len(metrics),
|
|
105
105
|
files_in_zone_of_pain=sum(1 for m in metrics if m.in_zone_of_pain),
|
|
106
|
-
files_in_zone_of_uselessness=sum(
|
|
107
|
-
1 for m in metrics if m.in_zone_of_uselessness
|
|
108
|
-
),
|
|
106
|
+
files_in_zone_of_uselessness=sum(1 for m in metrics if m.in_zone_of_uselessness),
|
|
109
107
|
total_files=len(files),
|
|
110
108
|
)
|
|
@@ -129,9 +129,7 @@ def _extract_class(node: ast.ClassDef, file_path: str) -> ClassInfo:
|
|
|
129
129
|
for item in ast.walk(node):
|
|
130
130
|
if isinstance(item, ast.Assign):
|
|
131
131
|
for target in item.targets:
|
|
132
|
-
if isinstance(target, ast.Attribute) and isinstance(
|
|
133
|
-
target.value, ast.Name
|
|
134
|
-
):
|
|
132
|
+
if isinstance(target, ast.Attribute) and isinstance(target.value, ast.Name):
|
|
135
133
|
if target.value.id == "self":
|
|
136
134
|
field_name = target.attr
|
|
137
135
|
if field_name not in fields:
|
|
@@ -142,9 +140,7 @@ def _extract_class(node: ast.ClassDef, file_path: str) -> ClassInfo:
|
|
|
142
140
|
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
143
141
|
method_name = item.name
|
|
144
142
|
accessed = _find_field_accesses(item, set(fields.keys()))
|
|
145
|
-
methods.append(
|
|
146
|
-
MethodInfo(name=method_name, accessed_fields=accessed)
|
|
147
|
-
)
|
|
143
|
+
methods.append(MethodInfo(name=method_name, accessed_fields=accessed))
|
|
148
144
|
# Update field access tracking
|
|
149
145
|
for field_name in accessed:
|
|
150
146
|
if field_name in fields:
|
|
@@ -159,9 +155,7 @@ def _extract_class(node: ast.ClassDef, file_path: str) -> ClassInfo:
|
|
|
159
155
|
)
|
|
160
156
|
|
|
161
157
|
|
|
162
|
-
def _extract_enhanced_class(
|
|
163
|
-
node: ast.ClassDef, file_path: str
|
|
164
|
-
) -> EnhancedClassInfo:
|
|
158
|
+
def _extract_enhanced_class(node: ast.ClassDef, file_path: str) -> EnhancedClassInfo:
|
|
165
159
|
"""Extract EnhancedClassInfo from a ClassDef AST node."""
|
|
166
160
|
base = _extract_class(node, file_path)
|
|
167
161
|
|
{archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/fluentapi/export_utils.py
RENAMED
|
@@ -35,11 +35,7 @@ class MetricsExporter:
|
|
|
35
35
|
HTML content as a string. Also writes to file if output_path specified.
|
|
36
36
|
"""
|
|
37
37
|
opts = options or ExportOptions()
|
|
38
|
-
timestamp = (
|
|
39
|
-
datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
40
|
-
if opts.include_timestamp
|
|
41
|
-
else ""
|
|
42
|
-
)
|
|
38
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") if opts.include_timestamp else ""
|
|
43
39
|
|
|
44
40
|
css = opts.custom_css or _DEFAULT_CSS
|
|
45
41
|
|
|
@@ -55,7 +51,7 @@ class MetricsExporter:
|
|
|
55
51
|
</head>
|
|
56
52
|
<body>
|
|
57
53
|
<h1>{opts.title}</h1>
|
|
58
|
-
{f'<p class="timestamp">Generated: {timestamp}</p>' if timestamp else
|
|
54
|
+
{f'<p class="timestamp">Generated: {timestamp}</p>' if timestamp else ""}
|
|
59
55
|
<table>
|
|
60
56
|
<thead>
|
|
61
57
|
<tr><th>Metric</th><th>Value</th></tr>
|
{archunitpython-1.2.0 → archunitpython-1.2.1}/src/archunitpython/metrics/fluentapi/metrics.py
RENAMED
|
@@ -97,9 +97,7 @@ class MetricsBuilder:
|
|
|
97
97
|
)
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
def _get_filtered_classes(
|
|
101
|
-
project_path: str | None, filters: list[Filter]
|
|
102
|
-
) -> list[ClassInfo]:
|
|
100
|
+
def _get_filtered_classes(project_path: str | None, filters: list[Filter]) -> list[ClassInfo]:
|
|
103
101
|
classes = extract_class_info(project_path)
|
|
104
102
|
if not filters:
|
|
105
103
|
return classes
|
|
@@ -119,39 +117,25 @@ class CountMetricsBuilder:
|
|
|
119
117
|
self._filters = filters
|
|
120
118
|
|
|
121
119
|
def method_count(self) -> "ClassMetricThresholdBuilder":
|
|
122
|
-
return ClassMetricThresholdBuilder(
|
|
123
|
-
self._project_path, self._filters, MethodCountMetric()
|
|
124
|
-
)
|
|
120
|
+
return ClassMetricThresholdBuilder(self._project_path, self._filters, MethodCountMetric())
|
|
125
121
|
|
|
126
122
|
def field_count(self) -> "ClassMetricThresholdBuilder":
|
|
127
|
-
return ClassMetricThresholdBuilder(
|
|
128
|
-
self._project_path, self._filters, FieldCountMetric()
|
|
129
|
-
)
|
|
123
|
+
return ClassMetricThresholdBuilder(self._project_path, self._filters, FieldCountMetric())
|
|
130
124
|
|
|
131
125
|
def lines_of_code(self) -> "FileMetricThresholdBuilder":
|
|
132
|
-
return FileMetricThresholdBuilder(
|
|
133
|
-
self._project_path, self._filters, LinesOfCodeMetric()
|
|
134
|
-
)
|
|
126
|
+
return FileMetricThresholdBuilder(self._project_path, self._filters, LinesOfCodeMetric())
|
|
135
127
|
|
|
136
128
|
def statements(self) -> "FileMetricThresholdBuilder":
|
|
137
|
-
return FileMetricThresholdBuilder(
|
|
138
|
-
self._project_path, self._filters, StatementCountMetric()
|
|
139
|
-
)
|
|
129
|
+
return FileMetricThresholdBuilder(self._project_path, self._filters, StatementCountMetric())
|
|
140
130
|
|
|
141
131
|
def imports(self) -> "FileMetricThresholdBuilder":
|
|
142
|
-
return FileMetricThresholdBuilder(
|
|
143
|
-
self._project_path, self._filters, ImportCountMetric()
|
|
144
|
-
)
|
|
132
|
+
return FileMetricThresholdBuilder(self._project_path, self._filters, ImportCountMetric())
|
|
145
133
|
|
|
146
134
|
def classes(self) -> "FileMetricThresholdBuilder":
|
|
147
|
-
return FileMetricThresholdBuilder(
|
|
148
|
-
self._project_path, self._filters, ClassCountMetric()
|
|
149
|
-
)
|
|
135
|
+
return FileMetricThresholdBuilder(self._project_path, self._filters, ClassCountMetric())
|
|
150
136
|
|
|
151
137
|
def functions(self) -> "FileMetricThresholdBuilder":
|
|
152
|
-
return FileMetricThresholdBuilder(
|
|
153
|
-
self._project_path, self._filters, FunctionCountMetric()
|
|
154
|
-
)
|
|
138
|
+
return FileMetricThresholdBuilder(self._project_path, self._filters, FunctionCountMetric())
|
|
155
139
|
|
|
156
140
|
|
|
157
141
|
class ClassMetricThresholdBuilder:
|
|
@@ -340,19 +324,13 @@ class DistanceMetricsBuilder:
|
|
|
340
324
|
self._filters = filters
|
|
341
325
|
|
|
342
326
|
def abstractness(self) -> "DistanceThresholdBuilder":
|
|
343
|
-
return DistanceThresholdBuilder(
|
|
344
|
-
self._project_path, self._filters, "abstractness"
|
|
345
|
-
)
|
|
327
|
+
return DistanceThresholdBuilder(self._project_path, self._filters, "abstractness")
|
|
346
328
|
|
|
347
329
|
def instability(self) -> "DistanceThresholdBuilder":
|
|
348
|
-
return DistanceThresholdBuilder(
|
|
349
|
-
self._project_path, self._filters, "instability"
|
|
350
|
-
)
|
|
330
|
+
return DistanceThresholdBuilder(self._project_path, self._filters, "instability")
|
|
351
331
|
|
|
352
332
|
def distance_from_main_sequence(self) -> "DistanceThresholdBuilder":
|
|
353
|
-
return DistanceThresholdBuilder(
|
|
354
|
-
self._project_path, self._filters, "distance"
|
|
355
|
-
)
|
|
333
|
+
return DistanceThresholdBuilder(self._project_path, self._filters, "distance")
|
|
356
334
|
|
|
357
335
|
def not_in_zone_of_pain(self) -> "ZoneCondition":
|
|
358
336
|
return ZoneCondition(self._project_path, self._filters, "pain")
|
|
@@ -440,11 +418,7 @@ class ZoneCondition:
|
|
|
440
418
|
|
|
441
419
|
for file_result in files:
|
|
442
420
|
dm = calculate_file_distance_metrics(file_result, files)
|
|
443
|
-
in_zone =
|
|
444
|
-
dm.in_zone_of_pain
|
|
445
|
-
if self._zone_type == "pain"
|
|
446
|
-
else dm.in_zone_of_uselessness
|
|
447
|
-
)
|
|
421
|
+
in_zone = dm.in_zone_of_pain if self._zone_type == "pain" else dm.in_zone_of_uselessness
|
|
448
422
|
|
|
449
423
|
if in_zone:
|
|
450
424
|
violations.append(
|