cleanarch 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ name: Python CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ workflow_dispatch:
9
+
10
+ permissions: {}
11
+
12
+ jobs:
13
+ validation:
14
+ name: 検査
15
+ runs-on: ubuntu-latest
16
+ timeout-minutes: 10
17
+ permissions:
18
+ contents: read
19
+ steps:
20
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
21
+ with:
22
+ persist-credentials: false
23
+
24
+ - name: uv のセットアップ
25
+ # setup-uv は major/minor タグを publish していないため commit hash でピンする
26
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
27
+ with:
28
+ python-version: "3.14"
29
+ enable-cache: true
30
+
31
+ - name: 依存の同期
32
+ # --locked で uv.lock と pyproject.toml のズレも検出する
33
+ run: uv sync --locked
34
+
35
+ - name: Ruff リント
36
+ run: uv run ruff check .
37
+
38
+ - name: 型チェック
39
+ run: uv run mypy
40
+
41
+ - name: テスト
42
+ run: uv run pytest
@@ -0,0 +1,75 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ # 既定は無権限。必要な job にだけ最小権限を与える。
8
+ permissions: {}
9
+
10
+ concurrency:
11
+ group: publish-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ build:
16
+ name: 配布物のビルド
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 10
19
+ permissions:
20
+ contents: read
21
+ steps:
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ persist-credentials: false
25
+
26
+ - name: uv のセットアップ
27
+ # setup-uv は major/minor タグを publish していないため commit hash でピンする
28
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
29
+ with:
30
+ python-version: "3.14"
31
+ # リリース成果物のビルドではキャッシュを使わない。
32
+ # PR 経由で汚染されたキャッシュが配布物に混入する経路を断つ (zizmor: cache-poisoning)。
33
+ enable-cache: false
34
+
35
+ - name: タグと pyproject.toml の version が一致することを検証
36
+ env:
37
+ TAG: ${{ github.event.release.tag_name }}
38
+ run: |
39
+ VERSION="$(python3 -c 'import tomllib, pathlib; print(tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"])')"
40
+ if [ "${TAG#v}" != "$VERSION" ]; then
41
+ echo "::error::タグ ${TAG} と pyproject.toml の version ${VERSION} が一致しません"
42
+ exit 1
43
+ fi
44
+
45
+ - name: sdist と wheel をビルド
46
+ run: uv build --out-dir dist
47
+
48
+ - name: 配布物を artifact として保存
49
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
50
+ with:
51
+ name: python-package-distributions
52
+ path: dist/
53
+
54
+ publish-to-pypi:
55
+ name: PyPI へ公開
56
+ needs: [ build ]
57
+ runs-on: ubuntu-latest
58
+ timeout-minutes: 10
59
+ environment:
60
+ name: pypi
61
+ url: https://pypi.org/p/cleanarch
62
+ permissions:
63
+ # OIDC トークンの発行に必須。workflow 単位ではなく job 単位で付与する (公式の強い推奨)
64
+ id-token: write
65
+ steps:
66
+ - name: 配布物を取得
67
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
68
+ with:
69
+ name: python-package-distributions
70
+ path: dist/
71
+
72
+ - name: PyPI へアップロード
73
+ # Trusted Publishing (OIDC) のため認証情報の指定は一切不要。
74
+ # v1.11.0 以降、Trusted Publishing 時は PEP 740 attestation が自動生成・添付される。
75
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -0,0 +1,133 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
130
+
131
+ # JetBrains IDE (IntelliJ IDEA / PyCharm)
132
+ # 各開発者のローカル設定なので git 管理しない
133
+ .idea/
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.5
2
+ Name: cleanarch
3
+ Version: 0.1.0
4
+ Summary: モジュラモノリス + DDD のアーキテクチャ契約を「設定ファイルではなく CLI」として配る検査ツール
5
+ Project-URL: Homepage, https://github.com/theindiehacker/clean-architecture
6
+ Project-URL: Repository, https://github.com/theindiehacker/clean-architecture
7
+ Author-email: taiyo tamura <gtaiyou24@gmail.com>
8
+ License-Expression: MIT
9
+ Keywords: architecture,ddd,import-linter,lint,modular-monolith
10
+ Requires-Python: >=3.14
11
+ Requires-Dist: import-linter==2.13
12
+ Description-Content-Type: text/markdown
13
+
14
+ # 🏗️ Clean Architecture
15
+
16
+ モジュラモノリス + DDD のアーキテクチャ契約を、**設定ファイルではなく CLI として配る**検査ツール。
17
+
18
+ ## 何が違うか
19
+
20
+ 通常 [import-linter](https://import-linter.readthedocs.io/) の契約は各リポジトリの `.importlinter` に書く。
21
+ モジュールが増えれば契約ファイルも増え、プロジェクトが増えれば同じ文面がコピーで増殖する。
22
+ そして中央で契約を 1 本足しても、どのリポジトリにも届かない。
23
+
24
+ `cleanarch` は契約を**このパッケージの中**に持つ。利用側が書くのは宣言 1 ブロックだけで、
25
+ 生成された契約はテンポラリファイルに書かれてそのまま捨てられる(リポジトリにコミットさせない
26
+ = 手で編集される余地を残さない)。契約を足したいときはこのパッケージのバージョンを上げる。
27
+
28
+ ## 生成される契約
29
+
30
+ | 契約 | 内容 |
31
+ |:--|:--|
32
+ | `{module}-layers` | ヘキサゴナルの依存方向(`port → application → domain`)を exhaustive で強制 |
33
+ | `{module}-inbound-adapters` | 入力アダプタから domain への直接依存を禁止(ユースケース境界の空洞化を防ぐ) |
34
+ | `{module}-encapsulation` | 他モジュールから内部層への参照を禁止。**source は「自分以外の全モジュール」から自動生成** |
35
+ | `{shared}-purity` | 共有カーネルから業務モジュールへの依存を禁止(逆流防止) |
36
+
37
+ `{module}-encapsulation` の source を自動生成しているのが効く。手書きの契約ファイルでは、
38
+ モジュールを 1 つ足したときに既存モジュール全部の `source_modules` へ追記する必要があり、
39
+ **漏れがそのまま境界の穴になる**(fastship.jp の `.importlinter` にもこの注意書きがある)。
40
+ 生成ならこの事故が起こらない。
41
+
42
+ ## 導入
43
+
44
+ ```bash
45
+ uv add --dev cleanarch
46
+ ```
47
+
48
+ ## 設定
49
+
50
+ ```toml
51
+ [tool.cleanarch]
52
+ src = "src"
53
+ modules = ["authority", "tenant", "notify"] # 省略時は src/* を自動検出
54
+ shared = ["common"]
55
+
56
+ # 既定値を上書きしたいとき
57
+ layers = ["port", "application", "domain"]
58
+ layer_ignores = ["core", "middleware", "exception", "settings"]
59
+ internal_layers = ["application", "domain", "port.adapter.persistence", "port.adapter.service"]
60
+ inbound_adapters = ["port.adapter.resource", "port.adapter.messaging"]
61
+
62
+ # 既存違反は負債として明示する。新規違反だけが CI を落とす。
63
+ debt = ["authority.port.adapter.resource.oauth.scopes_resource -> authority.domain.model.scope"]
64
+
65
+ # プロジェクト固有の契約
66
+ [[tool.cleanarch.forbidden]]
67
+ name = "redis-direct-access"
68
+ description = "RedisRegistry 以外からの redis 直接 import を禁止"
69
+ source_modules = ["authority", "tenant"]
70
+ forbidden_modules = ["redis"]
71
+
72
+ # フレームワーク実装の上書き(期限付きの負債)
73
+ [[tool.cleanarch.overrides]]
74
+ target = "authority.application.identity.IdentityApplicationService"
75
+ reason = "Identity Platform への資格情報移管。CredentialService ポートが未提供"
76
+ upstream = "https://github.com/theindiehacker/clean-architecture/issues/128"
77
+ sunset = 2026-12-31
78
+ ```
79
+
80
+ ## コマンド
81
+
82
+ ```bash
83
+ cleanarch check # 契約 + 上書き宣言を検査する(CI で使う。違反 or 期限切れで非 0 終了)
84
+ cleanarch contracts # 生成される import-linter 契約を表示する(デバッグ用)
85
+ cleanarch overrides # 上書き宣言の一覧と期限を表示する
86
+ ```
87
+
88
+ ## 負債と上書きを 1 箇所に集める
89
+
90
+ `debt` と `overrides` をプロジェクト全体で 1 箇所に集約しているのは、**総量を中央から観測する**ため。
91
+ 契約ファイルが 9 個に散っていると数えられない。
92
+
93
+ とくに `overrides` の一覧は、そのまま「フレームワークに足りない拡張点のバックログ」になる。
94
+ 同じ上書きが 2 案件で現れたら、拡張点の不足が確定した合図。
95
+
96
+ ## 開発
97
+
98
+ ```bash
99
+ task init # 依存インストール
100
+ task test # テスト
101
+ task style:check # ruff / mypy
102
+ ```
103
+
104
+ ## ライセンス
105
+
106
+ MIT
@@ -0,0 +1,93 @@
1
+ # 🏗️ Clean Architecture
2
+
3
+ モジュラモノリス + DDD のアーキテクチャ契約を、**設定ファイルではなく CLI として配る**検査ツール。
4
+
5
+ ## 何が違うか
6
+
7
+ 通常 [import-linter](https://import-linter.readthedocs.io/) の契約は各リポジトリの `.importlinter` に書く。
8
+ モジュールが増えれば契約ファイルも増え、プロジェクトが増えれば同じ文面がコピーで増殖する。
9
+ そして中央で契約を 1 本足しても、どのリポジトリにも届かない。
10
+
11
+ `cleanarch` は契約を**このパッケージの中**に持つ。利用側が書くのは宣言 1 ブロックだけで、
12
+ 生成された契約はテンポラリファイルに書かれてそのまま捨てられる(リポジトリにコミットさせない
13
+ = 手で編集される余地を残さない)。契約を足したいときはこのパッケージのバージョンを上げる。
14
+
15
+ ## 生成される契約
16
+
17
+ | 契約 | 内容 |
18
+ |:--|:--|
19
+ | `{module}-layers` | ヘキサゴナルの依存方向(`port → application → domain`)を exhaustive で強制 |
20
+ | `{module}-inbound-adapters` | 入力アダプタから domain への直接依存を禁止(ユースケース境界の空洞化を防ぐ) |
21
+ | `{module}-encapsulation` | 他モジュールから内部層への参照を禁止。**source は「自分以外の全モジュール」から自動生成** |
22
+ | `{shared}-purity` | 共有カーネルから業務モジュールへの依存を禁止(逆流防止) |
23
+
24
+ `{module}-encapsulation` の source を自動生成しているのが効く。手書きの契約ファイルでは、
25
+ モジュールを 1 つ足したときに既存モジュール全部の `source_modules` へ追記する必要があり、
26
+ **漏れがそのまま境界の穴になる**(fastship.jp の `.importlinter` にもこの注意書きがある)。
27
+ 生成ならこの事故が起こらない。
28
+
29
+ ## 導入
30
+
31
+ ```bash
32
+ uv add --dev cleanarch
33
+ ```
34
+
35
+ ## 設定
36
+
37
+ ```toml
38
+ [tool.cleanarch]
39
+ src = "src"
40
+ modules = ["authority", "tenant", "notify"] # 省略時は src/* を自動検出
41
+ shared = ["common"]
42
+
43
+ # 既定値を上書きしたいとき
44
+ layers = ["port", "application", "domain"]
45
+ layer_ignores = ["core", "middleware", "exception", "settings"]
46
+ internal_layers = ["application", "domain", "port.adapter.persistence", "port.adapter.service"]
47
+ inbound_adapters = ["port.adapter.resource", "port.adapter.messaging"]
48
+
49
+ # 既存違反は負債として明示する。新規違反だけが CI を落とす。
50
+ debt = ["authority.port.adapter.resource.oauth.scopes_resource -> authority.domain.model.scope"]
51
+
52
+ # プロジェクト固有の契約
53
+ [[tool.cleanarch.forbidden]]
54
+ name = "redis-direct-access"
55
+ description = "RedisRegistry 以外からの redis 直接 import を禁止"
56
+ source_modules = ["authority", "tenant"]
57
+ forbidden_modules = ["redis"]
58
+
59
+ # フレームワーク実装の上書き(期限付きの負債)
60
+ [[tool.cleanarch.overrides]]
61
+ target = "authority.application.identity.IdentityApplicationService"
62
+ reason = "Identity Platform への資格情報移管。CredentialService ポートが未提供"
63
+ upstream = "https://github.com/theindiehacker/clean-architecture/issues/128"
64
+ sunset = 2026-12-31
65
+ ```
66
+
67
+ ## コマンド
68
+
69
+ ```bash
70
+ cleanarch check # 契約 + 上書き宣言を検査する(CI で使う。違反 or 期限切れで非 0 終了)
71
+ cleanarch contracts # 生成される import-linter 契約を表示する(デバッグ用)
72
+ cleanarch overrides # 上書き宣言の一覧と期限を表示する
73
+ ```
74
+
75
+ ## 負債と上書きを 1 箇所に集める
76
+
77
+ `debt` と `overrides` をプロジェクト全体で 1 箇所に集約しているのは、**総量を中央から観測する**ため。
78
+ 契約ファイルが 9 個に散っていると数えられない。
79
+
80
+ とくに `overrides` の一覧は、そのまま「フレームワークに足りない拡張点のバックログ」になる。
81
+ 同じ上書きが 2 案件で現れたら、拡張点の不足が確定した合図。
82
+
83
+ ## 開発
84
+
85
+ ```bash
86
+ task init # 依存インストール
87
+ task test # テスト
88
+ task style:check # ruff / mypy
89
+ ```
90
+
91
+ ## ライセンス
92
+
93
+ MIT
@@ -0,0 +1,34 @@
1
+ version: '3'
2
+
3
+ tasks:
4
+ init:
5
+ desc: 開発環境のセットアップ
6
+ cmds:
7
+ - uv sync
8
+ - echo "✅ done"
9
+
10
+ test:
11
+ desc: テスト実行
12
+ cmd: uv run pytest {{.CLI_ARGS}}
13
+
14
+ style:check:
15
+ desc: スタイル / 型の検査
16
+ deps: [style:check:ruff, style:check:mypy]
17
+ cmds:
18
+ - echo "✅ clean-architecture"
19
+
20
+ style:check:ruff:
21
+ desc: Ruff リント
22
+ cmd: uv run ruff check .
23
+
24
+ style:check:mypy:
25
+ desc: 型チェック
26
+ cmd: uv run mypy
27
+
28
+ style:fix:
29
+ desc: スタイル自動修正
30
+ cmd: uv run ruff check --fix .
31
+
32
+ build:
33
+ desc: 配布物のビルド
34
+ cmd: uv build --out-dir dist
@@ -0,0 +1,4 @@
1
+ [tools]
2
+ python = "3.14"
3
+ "github:astral-sh/uv" = "latest"
4
+ task = "latest"
@@ -0,0 +1,108 @@
1
+ [project]
2
+ name = "cleanarch"
3
+ version = "0.1.0"
4
+ description = "モジュラモノリス + DDD のアーキテクチャ契約を「設定ファイルではなく CLI」として配る検査ツール"
5
+ readme = "README.md"
6
+ requires-python = ">=3.14"
7
+ license = "MIT"
8
+ authors = [{ name = "taiyo tamura", email = "gtaiyou24@gmail.com" }]
9
+ keywords = ["architecture", "import-linter", "modular-monolith", "ddd", "lint"]
10
+ dependencies = [
11
+ "import-linter==2.13",
12
+ ]
13
+
14
+ [project.scripts]
15
+ cleanarch = "cleanarchitecture.cli:main"
16
+
17
+ [project.urls]
18
+ Homepage = "https://github.com/theindiehacker/clean-architecture"
19
+ Repository = "https://github.com/theindiehacker/clean-architecture"
20
+
21
+ [build-system]
22
+ requires = ["hatchling"]
23
+ build-backend = "hatchling.build"
24
+
25
+ [tool.hatch.build.targets.wheel]
26
+ packages = ["src/cleanarchitecture"]
27
+
28
+ [dependency-groups]
29
+ dev = [
30
+ "mypy==2.1.0",
31
+ "pytest==9.1.1",
32
+ "ruff==0.15.21",
33
+ ]
34
+
35
+ # ============ 🪄 Ruff ============
36
+ # 利用側プロジェクトに配る規約と揃える (自分が守れない規約は配れない)。
37
+ [tool.ruff]
38
+ # src レイアウト。cleanarchitecture を第一パーティとして isort に認識させる。
39
+ src = ["src", "."]
40
+ target-version = "py314"
41
+ line-length = 120
42
+ indent-width = 4
43
+ extend-exclude = ["__init__.py"]
44
+
45
+ [tool.ruff.lint]
46
+ select = ["ALL"]
47
+ ignore = [
48
+ "B008",
49
+ "ERA001",
50
+ "FIX002",
51
+ "N818",
52
+ "PLR0913",
53
+ "RUF012",
54
+ "TRY003",
55
+ "FBT001",
56
+ "FBT002",
57
+ "PLC0415",
58
+ "PLW0108",
59
+ "A003",
60
+ "D",
61
+ "TD",
62
+ "ARG",
63
+ "EM",
64
+ ]
65
+
66
+ [tool.ruff.lint.per-file-ignores]
67
+ # CLI は標準出力が成果物。
68
+ "src/cleanarchitecture/cli.py" = ["T201"]
69
+ "src/cleanarchitecture/_lint_runner.py" = ["T201"]
70
+ "src/cleanarchitecture/overrides.py" = ["T201"]
71
+ # テストは日本語で仕様を書く (テスト名がそのまま仕様書になる)。
72
+ "test/**/*.py" = ["S101", "SLF001", "PLR2004", "INP001", "N801", "N802", "N803", "N806", "N999", "PLC2401", "RUF001", "RUF002", "RUF003",
73
+ # テストは fixture / tmp_path を実行時に受け取るため型限定 import へ移せない
74
+ "TC001", "TC002", "TC003",
75
+ # 期限判定は「今日」が基準。テストでも同じ基準を使う
76
+ "DTZ011"]
77
+
78
+ [tool.ruff.lint.pycodestyle]
79
+ max-line-length = 160
80
+
81
+ [tool.ruff.lint.flake8-annotations]
82
+ mypy-init-return = true
83
+
84
+ [tool.ruff.lint.flake8-tidy-imports]
85
+ ban-relative-imports = "all"
86
+
87
+ [tool.ruff.lint.isort.sections]
88
+ sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
89
+
90
+ # ============ ✔️ mypy ============
91
+ [tool.mypy]
92
+ python_version = 3.14
93
+ files = ["src", "test"]
94
+ mypy_path = ["src"]
95
+ color_output = true
96
+ show_column_numbers = true
97
+ check_untyped_defs = true
98
+ disallow_untyped_defs = true
99
+ no_implicit_optional = true
100
+ warn_redundant_casts = true
101
+ ignore_missing_imports = true
102
+ strict_optional = false
103
+ explicit_package_bases = true
104
+
105
+ # ============ 🧪 pytest ============
106
+ [tool.pytest.ini_options]
107
+ testpaths = ["test"]
108
+ pythonpath = ["src"]
@@ -0,0 +1,11 @@
1
+ """インストール済みメタデータからバージョンを読む。
2
+
3
+ バージョンの真実源は pyproject.toml の [project].version 一箇所。
4
+ 引数は import 名 (cleanarchitecture) ではなく配布名 (cleanarch)。
5
+ """
6
+
7
+ from importlib.metadata import version
8
+
9
+ __version__ = version("cleanarch")
10
+
11
+ __all__ = ["__version__"]
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ from cleanarchitecture.cli import main
4
+
5
+ sys.exit(main())
@@ -0,0 +1,24 @@
1
+ """import-linter を子プロセスとして実行するエントリポイント。
2
+
3
+ `python -m cleanarchitecture._lint_runner <生成した .ini>` として `cli` から起動される。
4
+ 別プロセスに分けるのは、import-linter が検査対象プロジェクトのソースを実際に import するため。
5
+ CLI 自身のプロセスに読み込ませると、利用側の import 副作用と sys.path 汚染を持ち込んでしまう。
6
+ """
7
+
8
+ import sys
9
+
10
+ from importlinter.application.use_cases import lint_imports
11
+ from importlinter.configuration import configure
12
+
13
+
14
+ def main(argv: list[str] | None = None) -> int:
15
+ args = sys.argv[1:] if argv is None else argv
16
+ if len(args) != 1:
17
+ print("usage: python -m cleanarchitecture._lint_runner <config.ini>", file=sys.stderr)
18
+ return 2
19
+ configure()
20
+ return 0 if lint_imports(config_filename=args[0], cache_dir=None) else 1
21
+
22
+
23
+ if __name__ == "__main__":
24
+ sys.exit(main())