archetype-py 0.2.3__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. {archetype_py-0.2.3 → archetype_py-0.3.0}/.github/workflows/archetype.yml +18 -3
  2. {archetype_py-0.2.3 → archetype_py-0.3.0}/.github/workflows/ci.yml +10 -1
  3. {archetype_py-0.2.3 → archetype_py-0.3.0}/.github/workflows/publish.yml +12 -2
  4. {archetype_py-0.2.3 → archetype_py-0.3.0}/CHANGELOG.md +16 -7
  5. archetype_py-0.3.0/PKG-INFO +101 -0
  6. archetype_py-0.3.0/PYPI.md +77 -0
  7. archetype_py-0.2.3/PKG-INFO → archetype_py-0.3.0/README.md +212 -24
  8. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/__init__.py +1 -2
  9. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/analysis/cache.py +13 -1
  10. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/analysis/git_utils.py +40 -1
  11. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/analysis/imports.py +128 -5
  12. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/analysis/models.py +1 -0
  13. archetype_py-0.3.0/archetype/analysis/path_filters.py +92 -0
  14. archetype_py-0.3.0/archetype/baseline.py +186 -0
  15. archetype_py-0.3.0/archetype/check.py +540 -0
  16. archetype_py-0.3.0/archetype/config.py +145 -0
  17. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/dsl/query.py +12 -4
  18. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/reporter.py +83 -2
  19. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/rule.py +66 -63
  20. {archetype_py-0.2.3 → archetype_py-0.3.0}/pyproject.toml +2 -2
  21. archetype_py-0.3.0/tests/fixtures/monorepo_project/libs/shared/src/acme/shared/utils.py +5 -0
  22. archetype_py-0.3.0/tests/fixtures/monorepo_project/services/billing/src/acme/billing/api.py +7 -0
  23. archetype_py-0.3.0/tests/fixtures/namespace_project/company/payments/api.py +7 -0
  24. archetype_py-0.3.0/tests/fixtures/namespace_project/company/shared/utils.py +5 -0
  25. archetype_py-0.3.0/tests/test_cli.py +1410 -0
  26. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_decorator_since.py +10 -2
  27. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_graph.py +125 -11
  28. archetype_py-0.3.0/tests/test_public_api.py +12 -0
  29. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_reporter.py +108 -1
  30. archetype_py-0.2.3/README.md +0 -321
  31. archetype_py-0.2.3/archetype/check.py +0 -182
  32. archetype_py-0.2.3/tests/test_cli.py +0 -668
  33. {archetype_py-0.2.3 → archetype_py-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  34. {archetype_py-0.2.3 → archetype_py-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  35. {archetype_py-0.2.3 → archetype_py-0.3.0}/.github/pull_request_template.md +0 -0
  36. {archetype_py-0.2.3 → archetype_py-0.3.0}/.gitignore +0 -0
  37. {archetype_py-0.2.3 → archetype_py-0.3.0}/BENCHMARKS.md +0 -0
  38. {archetype_py-0.2.3 → archetype_py-0.3.0}/CODE_OF_CONDUCT.md +0 -0
  39. {archetype_py-0.2.3 → archetype_py-0.3.0}/CONTRIBUTING.md +0 -0
  40. {archetype_py-0.2.3 → archetype_py-0.3.0}/LICENSE +0 -0
  41. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/analysis/__init__.py +0 -0
  42. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/analysis/ast_utils.py +0 -0
  43. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/analysis/init.py +0 -0
  44. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/analysis/pattern.py +0 -0
  45. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/dsl/__init__.py +0 -0
  46. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/dsl/init.py +0 -0
  47. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/init.py +0 -0
  48. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/plugin/__init__.py +0 -0
  49. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/plugin/init.py +0 -0
  50. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/plugin/pytest_plugin.py +0 -0
  51. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/rules/__init__.py +0 -0
  52. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/rules/boundaries.py +0 -0
  53. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/rules/cycles.py +0 -0
  54. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/rules/layers.py +0 -0
  55. {archetype_py-0.2.3 → archetype_py-0.3.0}/archetype/rules/naming.py +0 -0
  56. {archetype_py-0.2.3 → archetype_py-0.3.0}/architecture.py +0 -0
  57. {archetype_py-0.2.3 → archetype_py-0.3.0}/assets/Pytest.png +0 -0
  58. {archetype_py-0.2.3 → archetype_py-0.3.0}/assets/Rule_Execution_Flow.png +0 -0
  59. {archetype_py-0.2.3 → archetype_py-0.3.0}/assets/Violation_Lifecycle.png +0 -0
  60. {archetype_py-0.2.3 → archetype_py-0.3.0}/assets/architecture.png +0 -0
  61. {archetype_py-0.2.3 → archetype_py-0.3.0}/assets/ci_integration.png +0 -0
  62. {archetype_py-0.2.3 → archetype_py-0.3.0}/assets/logo.png +0 -0
  63. {archetype_py-0.2.3 → archetype_py-0.3.0}/benchmarks/README.md +0 -0
  64. {archetype_py-0.2.3 → archetype_py-0.3.0}/benchmarks/fixtures.py +0 -0
  65. {archetype_py-0.2.3 → archetype_py-0.3.0}/benchmarks/init.py +0 -0
  66. {archetype_py-0.2.3 → archetype_py-0.3.0}/benchmarks/run_benchmarks.py +0 -0
  67. {archetype_py-0.2.3 → archetype_py-0.3.0}/benchmarks/test_performance_regression.py +0 -0
  68. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/fixtures/simple_project/.gitignore +0 -0
  69. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/fixtures/simple_project/simple_project/api.py +0 -0
  70. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/fixtures/simple_project/simple_project/db.py +0 -0
  71. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/fixtures/simple_project/simple_project/internal/init.py +0 -0
  72. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/fixtures/simple_project/simple_project/internal/tokens.py +0 -0
  73. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/fixtures/simple_project/simple_project/main.py +0 -0
  74. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/fixtures/simple_project/simple_project/services.py +0 -0
  75. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_dsl.py +0 -0
  76. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_grouping.py +0 -0
  77. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_init.py +0 -0
  78. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_pattern.py +0 -0
  79. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_plugin.py +0 -0
  80. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_rule.py +0 -0
  81. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_rules_boundaries.py +0 -0
  82. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_rules_cycles.py +0 -0
  83. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_rules_layers.py +0 -0
  84. {archetype_py-0.2.3 → archetype_py-0.3.0}/tests/test_rules_naming.py +0 -0
@@ -4,8 +4,13 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - main
7
+ tags:
8
+ - "v*"
7
9
  pull_request:
8
10
 
11
+ permissions:
12
+ contents: read
13
+
9
14
  jobs:
10
15
  archetype:
11
16
  runs-on: ubuntu-latest
@@ -13,7 +18,11 @@ jobs:
13
18
  steps:
14
19
  # Pull down your repository code so CI can inspect it.
15
20
  - name: Checkout repository
16
- uses: actions/checkout@v4
21
+ uses: actions/checkout@v5
22
+ with:
23
+ token: ${{ github.token }}
24
+ ref: ${{ github.ref }}
25
+ fetch-depth: 0
17
26
 
18
27
  # Install Python 3.11 so the Archetype CLI can run.
19
28
  - name: Set up Python
@@ -28,9 +37,15 @@ jobs:
28
37
  pip install archetype-py
29
38
 
30
39
  # Run architecture rules defined in architecture.py.
31
- # This step exits non-zero on violations, which fails the workflow.
40
+ # If the installed Archetype supports GitHub annotations, emit inline
41
+ # PR annotations. Otherwise, fall back to standard checks.
32
42
  - name: Run architecture checks
33
- run: archetype check .
43
+ run: |
44
+ if archetype check --help | grep -q -- '--github-annotations'; then
45
+ archetype check . --github-annotations
46
+ else
47
+ archetype check .
48
+ fi
34
49
 
35
50
  # If your team already runs pytest in CI, you can skip this workflow file.
36
51
  # Archetype's pytest plugin runs architecture.py rules automatically during pytest.
@@ -4,8 +4,13 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - main
7
+ tags:
8
+ - "v*"
7
9
  pull_request:
8
10
 
11
+ permissions:
12
+ contents: read
13
+
9
14
  jobs:
10
15
  test:
11
16
  runs-on: ubuntu-latest
@@ -16,7 +21,11 @@ jobs:
16
21
 
17
22
  steps:
18
23
  - name: Checkout repository
19
- uses: actions/checkout@v4
24
+ uses: actions/checkout@v5
25
+ with:
26
+ token: ${{ github.token }}
27
+ ref: ${{ github.ref }}
28
+ fetch-depth: 0
20
29
 
21
30
  - name: Set up Python
22
31
  uses: actions/setup-python@v5
@@ -8,11 +8,17 @@ on:
8
8
  jobs:
9
9
  test:
10
10
  runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
11
13
 
12
14
  steps:
13
15
  # Checkout repository contents for test execution.
14
16
  - name: Checkout repository
15
- uses: actions/checkout@v4
17
+ uses: actions/checkout@v5
18
+ with:
19
+ token: ${{ github.token }}
20
+ ref: ${{ github.ref }}
21
+ fetch-depth: 0
16
22
 
17
23
  # Install Python runtime used for tests and packaging checks.
18
24
  - name: Set up Python
@@ -40,7 +46,11 @@ jobs:
40
46
  steps:
41
47
  # Checkout repository contents so the package can be built.
42
48
  - name: Checkout repository
43
- uses: actions/checkout@v4
49
+ uses: actions/checkout@v5
50
+ with:
51
+ token: ${{ github.token }}
52
+ ref: ${{ github.ref }}
53
+ fetch-depth: 0
44
54
 
45
55
  # Set up Python for building distribution artifacts.
46
56
  - name: Set up Python
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 - 2026-05-26
4
+
5
+ ### Added
6
+ - Git pre-commit hook integration via `archetype install-hook`.
7
+ - GitHub PR inline annotations support with `--github-annotations`.
8
+ - Baseline mode for legacy repositories via `--write-baseline` and `--baseline`.
9
+ - Project config defaults through `archetype.toml`.
10
+ - Exclude paths support via CLI (`--exclude`) and config.
11
+ - Versioned JSON contract with explicit `schema_version`.
12
+ - Namespace package and monorepo layout support improvements.
13
+ - Changed-files mode with `--changed-from <git-ref>`.
14
+
15
+ ### Changed
16
+ - CI/release workflows expanded to cover new check and packaging behaviors.
17
+
3
18
  ## 0.1.0 - 2026-05-09
4
19
 
5
20
  ### Added
@@ -48,12 +63,6 @@
48
63
  ## 0.2.3 — 2026-05-16
49
64
 
50
65
  ### Added
51
- - @warn decorator for non-blocking rule violations
52
- - @skip decorator to temporarily disable rules
53
- - @since decorator for date-scoped enforcement
54
- - @rule timeout parameter for pathological graphs
55
- - Glob pattern support in module matching
56
- - Rule grouping with group context manager
57
66
  - archetype init command for scaffolding
58
67
  - --quiet flag to show only failures and warnings
59
68
  - --format json flag for machine-readable output
@@ -67,4 +76,4 @@
67
76
  - src layout detection in archetype init
68
77
  - Verbose violation messages now concise and scannable
69
78
  - --quiet flag correctly filters JSON output
70
- - Naming convention violation message format cleaned up
79
+ - Naming convention violation message format cleaned up
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.4
2
+ Name: archetype-py
3
+ Version: 0.3.0
4
+ Summary: Enforce architectural rules as code. Catch structural violations before they merge.
5
+ Project-URL: Homepage, https://github.com/MossabArektout/archetype-py
6
+ Project-URL: Documentation, https://github.com/MossabArektout/archetype-py
7
+ Author-email: Mossab Arektout <mossabarektout2000@gmail.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Software Development :: Quality Assurance
15
+ Requires-Python: >=3.11
16
+ Requires-Dist: click
17
+ Requires-Dist: networkx
18
+ Requires-Dist: rich
19
+ Provides-Extra: benchmarks
20
+ Provides-Extra: dev
21
+ Requires-Dist: hatch; extra == 'dev'
22
+ Requires-Dist: pytest; extra == 'dev'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # archetype-py
26
+
27
+ Enforce architectural rules as code. Catch structural violations before they merge.
28
+
29
+ [GitHub Repository](https://github.com/MossabArektout/archetype-py)
30
+ [Documentation](https://github.com/MossabArektout/archetype-py#readme)
31
+
32
+ ## Why archetype-py
33
+
34
+ Most tooling checks formatting, typing, and tests, but not architecture drift.
35
+ `archetype-py` lets you codify structural boundaries and enforce them in local runs, CI, and pytest.
36
+
37
+ ## When to use / When not to use
38
+
39
+ Use archetype-py when:
40
+ - You want architecture rules to run automatically in CI and pytest.
41
+ - You need to prevent forbidden imports, layer violations, or import cycles.
42
+ - You are adopting architecture checks incrementally in a legacy codebase (baseline mode).
43
+
44
+ Do not use archetype-py when:
45
+ - You only need style/type checks (linters and type checkers are enough).
46
+ - Your project is a very small script with no meaningful module boundaries.
47
+ - You are looking for runtime policy enforcement instead of static import-graph checks.
48
+
49
+ ## Install
50
+
51
+ ```bash
52
+ pip install archetype-py
53
+ ```
54
+
55
+ ## Quick Start
56
+
57
+ ```bash
58
+ archetype init .
59
+ archetype check .
60
+ ```
61
+
62
+ Create an `architecture.py` file and define your rules:
63
+
64
+ ```python
65
+ from archetype import rule
66
+ from archetype.rules import layers
67
+
68
+ @rule("layers are ordered")
69
+ def layer_order() -> None:
70
+ layers(["myapp.api", "myapp.services", "myapp.db"]).are_ordered()
71
+ ```
72
+
73
+ ## Core Features
74
+
75
+ - Architecture rules for forbidden imports, allowlisted imports, and protected boundaries
76
+ - Transitive dependency checks with `must_not_depend_on`
77
+ - Layer order enforcement with `layers(...).are_ordered()`
78
+ - Import cycle detection with `no_cycles(...)`
79
+ - Rule decorators: `@rule`, `@warn`, `@skip`, `@since`
80
+ - Rule grouping via `group("...")` and targeted execution with `--group`
81
+ - `archetype init` scaffolding for starter `architecture.py`
82
+ - JSON and text reporting (`--format json|text`) with stable JSON contract versioning
83
+ - Quiet output mode (`--quiet`) for CI-friendly logs
84
+ - Import graph caching for faster repeated runs (`--cache`, `--no-cache`)
85
+ - Parallel execution control with `--workers`
86
+ - Baseline adoption for legacy codebases (`--write-baseline`, `--baseline`)
87
+ - Changed-files scope mode (`--changed-from <git-ref>`)
88
+ - GitHub Actions inline PR annotations (`--github-annotations`)
89
+ - Path exclusions via CLI (`--exclude`) and config
90
+ - Project config defaults through `archetype.toml`
91
+ - Git pre-commit hook installer (`archetype install-hook`)
92
+ - Project layout support for flat, `src/`, namespace packages (PEP 420), and monorepos
93
+ - CLI command and pytest plugin support for local and CI enforcement
94
+
95
+ ## CI Example
96
+
97
+ ```yaml
98
+ - run: archetype check .
99
+ ```
100
+
101
+ For full guides, examples, and release notes, use the GitHub README and changelog.
@@ -0,0 +1,77 @@
1
+ # archetype-py
2
+
3
+ Enforce architectural rules as code. Catch structural violations before they merge.
4
+
5
+ [GitHub Repository](https://github.com/MossabArektout/archetype-py)
6
+ [Documentation](https://github.com/MossabArektout/archetype-py#readme)
7
+
8
+ ## Why archetype-py
9
+
10
+ Most tooling checks formatting, typing, and tests, but not architecture drift.
11
+ `archetype-py` lets you codify structural boundaries and enforce them in local runs, CI, and pytest.
12
+
13
+ ## When to use / When not to use
14
+
15
+ Use archetype-py when:
16
+ - You want architecture rules to run automatically in CI and pytest.
17
+ - You need to prevent forbidden imports, layer violations, or import cycles.
18
+ - You are adopting architecture checks incrementally in a legacy codebase (baseline mode).
19
+
20
+ Do not use archetype-py when:
21
+ - You only need style/type checks (linters and type checkers are enough).
22
+ - Your project is a very small script with no meaningful module boundaries.
23
+ - You are looking for runtime policy enforcement instead of static import-graph checks.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ pip install archetype-py
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```bash
34
+ archetype init .
35
+ archetype check .
36
+ ```
37
+
38
+ Create an `architecture.py` file and define your rules:
39
+
40
+ ```python
41
+ from archetype import rule
42
+ from archetype.rules import layers
43
+
44
+ @rule("layers are ordered")
45
+ def layer_order() -> None:
46
+ layers(["myapp.api", "myapp.services", "myapp.db"]).are_ordered()
47
+ ```
48
+
49
+ ## Core Features
50
+
51
+ - Architecture rules for forbidden imports, allowlisted imports, and protected boundaries
52
+ - Transitive dependency checks with `must_not_depend_on`
53
+ - Layer order enforcement with `layers(...).are_ordered()`
54
+ - Import cycle detection with `no_cycles(...)`
55
+ - Rule decorators: `@rule`, `@warn`, `@skip`, `@since`
56
+ - Rule grouping via `group("...")` and targeted execution with `--group`
57
+ - `archetype init` scaffolding for starter `architecture.py`
58
+ - JSON and text reporting (`--format json|text`) with stable JSON contract versioning
59
+ - Quiet output mode (`--quiet`) for CI-friendly logs
60
+ - Import graph caching for faster repeated runs (`--cache`, `--no-cache`)
61
+ - Parallel execution control with `--workers`
62
+ - Baseline adoption for legacy codebases (`--write-baseline`, `--baseline`)
63
+ - Changed-files scope mode (`--changed-from <git-ref>`)
64
+ - GitHub Actions inline PR annotations (`--github-annotations`)
65
+ - Path exclusions via CLI (`--exclude`) and config
66
+ - Project config defaults through `archetype.toml`
67
+ - Git pre-commit hook installer (`archetype install-hook`)
68
+ - Project layout support for flat, `src/`, namespace packages (PEP 420), and monorepos
69
+ - CLI command and pytest plugin support for local and CI enforcement
70
+
71
+ ## CI Example
72
+
73
+ ```yaml
74
+ - run: archetype check .
75
+ ```
76
+
77
+ For full guides, examples, and release notes, use the GitHub README and changelog.
@@ -1,27 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: archetype-py
3
- Version: 0.2.3
4
- Summary: Enforce architectural rules as code. Catch structural violations before they merge.
5
- Project-URL: Homepage, https://github.com/MossabArektout/archetype-py
6
- Project-URL: Documentation, https://github.com/MossabArektout/archetype-py
7
- Author-email: Mossab Arektout <mossabarektout2000@gmail.com>
8
- License: MIT
9
- License-File: LICENSE
10
- Classifier: Development Status :: 3 - Alpha
11
- Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Programming Language :: Python :: 3
14
- Classifier: Topic :: Software Development :: Quality Assurance
15
- Requires-Python: >=3.11
16
- Requires-Dist: click
17
- Requires-Dist: networkx
18
- Requires-Dist: rich
19
- Provides-Extra: benchmarks
20
- Provides-Extra: dev
21
- Requires-Dist: hatch; extra == 'dev'
22
- Requires-Dist: pytest; extra == 'dev'
23
- Description-Content-Type: text/markdown
24
-
25
1
  [![PyPI version](https://img.shields.io/pypi/v/archetype-py)](https://pypi.org/project/archetype-py/)
26
2
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://pypi.org/project/archetype-py/)
27
3
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/MossabArektout/archetype-py/blob/main/LICENSE)
@@ -40,6 +16,7 @@ Description-Content-Type: text/markdown
40
16
  - [Minimum `architecture.py` Example](#minimum-architecturepy-example)
41
17
  - [Features](#features)
42
18
  - [Decorators and Commands](#decorators-and-commands)
19
+ - [Baseline Mode](#baseline-mode)
43
20
  - [Perfect For](#perfect-for)
44
21
  - [Installation](#installation)
45
22
  - [Build & Test](#build--test)
@@ -229,11 +206,21 @@ def no_import_cycles() -> None:
229
206
  - Import cycle detection
230
207
  - Protected module boundaries
231
208
 
209
+ ### Project Layout Support
210
+ - Flat package layouts
211
+ - Single `src/` layouts
212
+ - Namespace packages (PEP 420, without `__init__.py`)
213
+ - Monorepos with multiple `src` roots
214
+
232
215
  ### Workflow Features
233
216
  - Rule grouping
234
217
  - Warning-level rules
235
218
  - Temporary rule skips with context
236
219
  - Changed-file enforcement (`since`)
220
+ - Legacy baseline snapshot/suppression (`--write-baseline`, `--baseline`)
221
+ - Diff-scoped checks (`--changed-from <ref>`)
222
+ - First-class project config defaults (`archetype.toml`)
223
+ - Path exclusions (`--exclude`, `archetype.toml`, legacy `[tool.archetype].exclude`)
237
224
  - Pytest integration
238
225
  - CI-friendly exit codes
239
226
 
@@ -251,13 +238,211 @@ Rules are written in `architecture.py` with decorators. Below are all decorator-
251
238
 
252
239
  Decorator order tip: place `@rule(...)` first, then wrappers like `@warn`, `@skip`, or `@since`.
253
240
 
241
+ ### `@since` Date Format
242
+
243
+ `@since(...)` only accepts ISO calendar dates in `YYYY-MM-DD` format. The
244
+ decorator validates this when `architecture.py` is loaded, so invalid values
245
+ raise a clear `ValueError` instead of being ignored.
246
+
247
+ ```python
248
+ @since("2026-01-01") # valid
249
+ def recent_violations_only() -> None:
250
+ ...
251
+
252
+ @since("01-01-2026") # invalid: expected YYYY-MM-DD
253
+ def ambiguous_date() -> None:
254
+ ...
255
+ ```
256
+
257
+ Invalid dates show the expectation in the error message:
258
+
259
+ ```text
260
+ Invalid date '01-01-2026'. Expected format: YYYY-MM-DD.
261
+ ```
262
+
254
263
  | Command | Description | Example |
255
264
  |---|---|---|
256
265
  | `archetype init [path]` | Detects project structure and generates a starter `architecture.py` file. | `archetype init .` |
257
266
  | `archetype check [path]` | Loads `architecture.py` and runs all registered architecture rules. | `archetype check .` |
258
267
  | `archetype check [path] --group <name>` | Runs only rules that belong to the specified group. | `archetype check . --group core` |
268
+ | `archetype check [path] --exclude <pattern>` | Excludes paths from analysis and reporting (repeatable). | `archetype check . --exclude /vendor/ --exclude /migrations/` |
269
+ | `archetype check [path] --write-baseline <file> --baseline <file>` | Writes a baseline snapshot and suppresses matching legacy violations so only new ones fail. | `archetype check . --baseline archetype-baseline.json` |
270
+ | `archetype check [path] --changed-from <ref>` | Limits reported violations to files changed since `<ref>` (branch name or commit SHA). | `archetype check . --changed-from origin/main` |
271
+ | `archetype check [path] --github-annotations` | Emits GitHub Actions inline annotations (`::error`/`::warning`) for PR diffs. | `archetype check . --github-annotations` |
272
+ | `archetype install-hook [path]` | Installs (or updates) a managed git pre-commit hook that runs `archetype check` before each commit. | `archetype install-hook .` |
273
+
274
+ ### Excluding Paths
275
+
276
+ Exclude noisy folders such as generated code, migrations, or vendored dependencies:
277
+
278
+ ```bash
279
+ archetype check . --exclude /vendor/ --exclude /migrations/
280
+ ```
281
+
282
+ You can also define defaults in `archetype.toml`:
283
+
284
+ ```toml
285
+ exclude = ["/vendor/", "/migrations/"]
286
+ ```
287
+
288
+ Legacy compatibility: if `archetype.toml` is missing, Archetype still reads
289
+ `[tool.archetype]` from `pyproject.toml`.
290
+
291
+ ### Project Config (`archetype.toml`)
292
+
293
+ Archetype auto-discovers `archetype.toml` in the project root passed to
294
+ `archetype check [path]`.
295
+
296
+ Supported defaults:
297
+
298
+ - `format` (`"text"` or `"json"`)
299
+ - `quiet` (`true`/`false`)
300
+ - `group` (`string`)
301
+ - `exclude` (`string` or `string[]`)
302
+ - `workers` (`int >= 1`)
303
+ - `cache` (`true`/`false`)
304
+
305
+ Example:
306
+
307
+ ```toml
308
+ format = "json"
309
+ quiet = true
310
+ group = "Layer boundaries"
311
+ exclude = ["/vendor/", "/migrations/"]
312
+ workers = 4
313
+ cache = true
314
+ ```
315
+
316
+ Precedence:
317
+
318
+ - CLI flags override `archetype.toml`.
319
+ - `archetype.toml` overrides built-in defaults.
320
+ - If config is missing, behavior remains unchanged.
321
+
322
+ ### Pre-commit Hook
323
+
324
+ Install a git pre-commit hook in one command:
259
325
 
326
+ ```bash
327
+ archetype install-hook .
328
+ ```
329
+
330
+ Behavior:
331
+
332
+ - Creates `.git/hooks/pre-commit` if missing.
333
+ - Appends an Archetype-managed block if a custom pre-commit hook already exists.
334
+ - Updates the managed block if Archetype already installed it.
335
+ - Blocks the commit when `archetype check` fails, and prints violations directly in the commit terminal output.
336
+
337
+ ### Changed-files Mode
338
+
339
+ Use diff scope to speed up checks in large repositories:
340
+
341
+ ```bash
342
+ archetype check . --changed-from origin/main
343
+ ```
344
+
345
+ `<ref>` can be a branch name (for example `origin/main`) or a commit SHA.
346
+
347
+ When enabled:
348
+ - Text output shows a scope banner with mode, ref, and changed file count.
349
+ - JSON output includes a `scope` object with mode/ref/file metadata.
350
+
351
+ ### GitHub PR Annotations
352
+
353
+ Use GitHub Actions annotations to surface violations directly on PR diff lines:
354
+
355
+ ```bash
356
+ archetype check . --github-annotations
357
+ ```
358
+
359
+ In GitHub Actions, these appear as inline file/line annotations for each violation
360
+ while preserving the normal non-zero exit code when checks fail.
260
361
 
362
+ ## Baseline Mode
363
+
364
+ Use baseline mode to adopt archetype in legacy repos without failing on pre-existing violations.
365
+
366
+ Create a baseline snapshot:
367
+
368
+ ```bash
369
+ archetype check . --write-baseline archetype-baseline.json
370
+ ```
371
+
372
+ Run checks against that baseline (matching old violations are suppressed):
373
+
374
+ ```bash
375
+ archetype check . --baseline archetype-baseline.json
376
+ ```
377
+
378
+ You can combine with JSON output to track counts:
379
+
380
+ ```bash
381
+ archetype check . --baseline archetype-baseline.json --format json
382
+ ```
383
+
384
+ JSON output includes:
385
+ - `schema_version`: top-level contract version for machine consumers
386
+ - `summary`: rule-level pass/fail/warn/skip counts
387
+ - `violations.total`: total current violations before suppression
388
+ - `violations.new`: violations not found in the baseline
389
+ - `violations.suppressed`: violations matched and suppressed by baseline
390
+
391
+ ### JSON Contract (Versioned)
392
+
393
+ Archetype JSON output is versioned for CI and other integrations.
394
+
395
+ Current contract version:
396
+
397
+ - `schema_version: 1`
398
+
399
+ Versioning policy:
400
+
401
+ - Non-breaking additions (for example new optional fields) keep the same `schema_version`.
402
+ - Breaking shape changes (rename/remove/type changes) must increment `schema_version`.
403
+ - Contract tests in CI enforce the current schema shape.
404
+
405
+ Field definitions:
406
+
407
+ - `schema_version` (`int`): machine-readable contract version.
408
+ - `summary` (`object`): counts by rule status.
409
+ - `violations` (`object`): aggregate violation counts.
410
+ - `rules` (`array`): per-rule results with status and violations.
411
+ - `scope` (`object`, optional): present when `--changed-from` is used.
412
+
413
+ Example (`--format json`):
414
+
415
+ ```json
416
+ {
417
+ "schema_version": 1,
418
+ "summary": {
419
+ "passed": 2,
420
+ "failed": 1,
421
+ "warned": 0,
422
+ "skipped": 0,
423
+ "total": 3
424
+ },
425
+ "violations": {
426
+ "total": 1,
427
+ "new": 1,
428
+ "suppressed": 0
429
+ },
430
+ "rules": [
431
+ {
432
+ "name": "api-must-not-import-db",
433
+ "status": "failed",
434
+ "group": "core",
435
+ "since_date": null,
436
+ "violations": [
437
+ {
438
+ "module": "simple_project.api",
439
+ "message": "Module 'simple_project.api' must not import 'simple_project.db'"
440
+ }
441
+ ]
442
+ }
443
+ ]
444
+ }
445
+ ```
261
446
 
262
447
  ## Perfect For
263
448
 
@@ -298,6 +483,8 @@ archetype check .
298
483
  - `0`: no blocking failures (passes and warnings only)
299
484
  - `1`: one or more blocking rule failures
300
485
 
486
+ When `--baseline` is used, exit code `1` means there are **new** blocking violations not present in the baseline.
487
+
301
488
  ---
302
489
 
303
490
  ## Troubleshooting
@@ -306,6 +493,7 @@ archetype check .
306
493
  - Rules seem to do nothing: confirm your rules are decorated with `@rule("...")`; undecorated functions are not registered.
307
494
  - `@since(...)` behavior is unexpected: verify the date format is `YYYY-MM-DD` and that your git history is available in the checked path.
308
495
  - Import path mismatches: use fully qualified module paths (`myapp.api`, not file paths like `src/api.py`).
496
+ - Namespace package imports not showing up: ensure modules live under discovered package roots (repo root, top-level `src/`, or nested monorepo `*/src` roots).
309
497
 
310
498
  ---
311
499
 
@@ -2,8 +2,7 @@
2
2
 
3
3
  from archetype.dsl.query import imports, load_project
4
4
  from archetype.rule import group, registry, rule, since, skip, warn
5
-
6
- module = None
5
+ from archetype.rules import module
7
6
 
8
7
  __all__ = [
9
8
  "rule",
@@ -4,19 +4,27 @@ from __future__ import annotations
4
4
 
5
5
  import pickle
6
6
  from pathlib import Path
7
+ from typing import Iterable
7
8
 
8
9
  import networkx as nx
9
10
 
11
+ from archetype.analysis.path_filters import is_path_excluded, normalize_exclude_patterns
12
+
10
13
 
11
14
  def get_cache_path(project_root: Path) -> Path:
12
15
  """Return the cache file path for a project."""
13
16
  return project_root.resolve() / ".archetype_cache"
14
17
 
15
18
 
16
- def compute_file_signatures(project_root: Path) -> dict[str, float]:
19
+ def compute_file_signatures(
20
+ project_root: Path,
21
+ *,
22
+ exclude_patterns: Iterable[str] | None = None,
23
+ ) -> dict[str, float]:
17
24
  """Compute mtime signatures for Python files under project_root."""
18
25
  signatures: dict[str, float] = {}
19
26
  root = project_root.resolve()
27
+ normalized_excludes = normalize_exclude_patterns(exclude_patterns)
20
28
 
21
29
  for file_path in root.rglob("*.py"):
22
30
  parts = file_path.parts
@@ -24,7 +32,11 @@ def compute_file_signatures(project_root: Path) -> dict[str, float]:
24
32
  continue
25
33
  if ".venv" in parts or "venv" in parts or "site-packages" in parts:
26
34
  continue
35
+ if is_path_excluded(file_path, root, normalized_excludes):
36
+ continue
27
37
  signatures[str(file_path.resolve())] = file_path.stat().st_mtime
38
+ for excluded in normalized_excludes:
39
+ signatures[f"__archetype_exclude__:{excluded}"] = -1.0
28
40
 
29
41
  return signatures
30
42