python-dependency-linter 0.1.0__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.
- python_dependency_linter-0.3.0/.claude/skills/commit/SKILL.md +24 -0
- python_dependency_linter-0.3.0/.claude/skills/release/SKILL.md +14 -0
- python_dependency_linter-0.3.0/.github/ISSUE_TEMPLATE/bug_report.yml +62 -0
- python_dependency_linter-0.3.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- python_dependency_linter-0.3.0/.github/ISSUE_TEMPLATE/feature_request.yml +37 -0
- python_dependency_linter-0.3.0/.github/pull_request_template.md +27 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/.github/workflows/ci.yaml +8 -4
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/.github/workflows/publish.yaml +4 -4
- python_dependency_linter-0.3.0/CHANGELOG.md +73 -0
- python_dependency_linter-0.3.0/CLAUDE.md +9 -0
- python_dependency_linter-0.3.0/CONTRIBUTING.md +84 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/PKG-INFO +159 -2
- python_dependency_linter-0.3.0/README.md +332 -0
- python_dependency_linter-0.3.0/pyproject.toml +95 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/python_dependency_linter/cli.py +40 -5
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/python_dependency_linter/config.py +12 -2
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/python_dependency_linter/matcher.py +19 -7
- python_dependency_linter-0.3.0/python_dependency_linter/parser.py +60 -0
- python_dependency_linter-0.3.0/tests/fixtures/sample_project/contexts/boards/__init__.py +1 -0
- python_dependency_linter-0.3.0/tests/fixtures/sample_project/contexts/boards/adapters/repository.py +7 -0
- python_dependency_linter-0.3.0/tests/test_cli.py +171 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/test_config.py +40 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/test_matcher.py +32 -0
- python_dependency_linter-0.3.0/tests/test_parser.py +74 -0
- python_dependency_linter-0.3.0/uv.lock +368 -0
- python_dependency_linter-0.1.0/README.md +0 -175
- python_dependency_linter-0.1.0/cliff.toml +0 -38
- python_dependency_linter-0.1.0/docs/superpowers/plans/2026-03-30-python-dependency-linter.md +0 -1343
- python_dependency_linter-0.1.0/docs/superpowers/specs/2026-03-30-python-dependency-linter-design.md +0 -235
- python_dependency_linter-0.1.0/pyproject.toml +0 -49
- python_dependency_linter-0.1.0/python_dependency_linter/parser.py +0 -27
- python_dependency_linter-0.1.0/tests/fixtures/sample_project/contexts/boards/adapters/repository.py +0 -3
- python_dependency_linter-0.1.0/tests/fixtures/sample_project/contexts/boards/domain/__init__.py +0 -0
- python_dependency_linter-0.1.0/tests/test_cli.py +0 -69
- python_dependency_linter-0.1.0/tests/test_parser.py +0 -30
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/.github/dependabot.yml +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/.gitignore +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/.pre-commit-config.yaml +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/.pre-commit-hooks.yaml +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/LICENSE +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/python_dependency_linter/__init__.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/python_dependency_linter/checker.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/python_dependency_linter/reporter.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/python_dependency_linter/resolver.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_config.yaml +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_project/contexts/__init__.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_project/contexts/auth/__init__.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_project/contexts/auth/application/__init__.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_project/contexts/auth/application/service.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_project/contexts/auth/domain/__init__.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_project/contexts/auth/domain/models.py +0 -0
- {python_dependency_linter-0.1.0/tests/fixtures/sample_project/contexts/boards → python_dependency_linter-0.3.0/tests/fixtures/sample_project/contexts/boards/adapters}/__init__.py +0 -0
- {python_dependency_linter-0.1.0/tests/fixtures/sample_project/contexts/boards/adapters → python_dependency_linter-0.3.0/tests/fixtures/sample_project/contexts/boards/application}/__init__.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_project/contexts/boards/application/service.py +0 -0
- {python_dependency_linter-0.1.0/tests/fixtures/sample_project/contexts/boards/application → python_dependency_linter-0.3.0/tests/fixtures/sample_project/contexts/boards/domain}/__init__.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_project/contexts/boards/domain/models.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/fixtures/sample_pyproject.toml +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/test_checker.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/test_reporter.py +0 -0
- {python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/tests/test_resolver.py +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit
|
|
3
|
+
description: Create a git commit following the project's commit convention
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Create a git commit following the project's commit convention defined in [CONTRIBUTING.md](../../../CONTRIBUTING.md).
|
|
7
|
+
|
|
8
|
+
## Steps
|
|
9
|
+
|
|
10
|
+
1. Read `CONTRIBUTING.md` to check the commit convention.
|
|
11
|
+
2. Run `git status` and `git diff` to review all changes.
|
|
12
|
+
3. Draft a commit message following the convention.
|
|
13
|
+
4. Stage only relevant files (do NOT use `git add -A`). Exclude secrets and unrelated files.
|
|
14
|
+
5. Commit using a HEREDOC for proper formatting:
|
|
15
|
+
```bash
|
|
16
|
+
git commit -m "$(cat <<'EOF'
|
|
17
|
+
<commit message here>
|
|
18
|
+
|
|
19
|
+
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
|
20
|
+
EOF
|
|
21
|
+
)"
|
|
22
|
+
```
|
|
23
|
+
6. Run `git status` to verify success.
|
|
24
|
+
7. If pre-commit hook fails, fix the issue and create a **new** commit (never amend).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release
|
|
3
|
+
description: Create a new release by calculating the next version from conventional commits and pushing a git tag
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Create a new release following the project's release process defined in [CONTRIBUTING.md](../../../CONTRIBUTING.md).
|
|
7
|
+
|
|
8
|
+
The release workflow is defined in [.github/workflows/publish.yaml](../../../.github/workflows/publish.yaml).
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. Read `CONTRIBUTING.md` to check the release process.
|
|
13
|
+
2. Follow the steps described in the Release section.
|
|
14
|
+
3. Ask the user to confirm the version before creating and pushing the tag.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Report a bug or unexpected behavior
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for reporting a bug! Please fill out the sections below.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: description
|
|
12
|
+
attributes:
|
|
13
|
+
label: Description
|
|
14
|
+
description: A clear description of what the bug is.
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: reproduce
|
|
20
|
+
attributes:
|
|
21
|
+
label: Steps to reproduce
|
|
22
|
+
description: Steps to reproduce the behavior.
|
|
23
|
+
placeholder: |
|
|
24
|
+
1. Create a config file with ...
|
|
25
|
+
2. Run `pdl check`
|
|
26
|
+
3. See error ...
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
|
|
30
|
+
- type: textarea
|
|
31
|
+
id: expected
|
|
32
|
+
attributes:
|
|
33
|
+
label: Expected behavior
|
|
34
|
+
description: What you expected to happen.
|
|
35
|
+
validations:
|
|
36
|
+
required: true
|
|
37
|
+
|
|
38
|
+
- type: textarea
|
|
39
|
+
id: config
|
|
40
|
+
attributes:
|
|
41
|
+
label: Configuration
|
|
42
|
+
description: Your `.python-dependency-linter.yaml` (remove sensitive info).
|
|
43
|
+
render: yaml
|
|
44
|
+
|
|
45
|
+
- type: textarea
|
|
46
|
+
id: environment
|
|
47
|
+
attributes:
|
|
48
|
+
label: Environment
|
|
49
|
+
description: Please provide the following info.
|
|
50
|
+
value: |
|
|
51
|
+
- OS:
|
|
52
|
+
- Python version:
|
|
53
|
+
- python-dependency-linter version:
|
|
54
|
+
validations:
|
|
55
|
+
required: true
|
|
56
|
+
|
|
57
|
+
- type: textarea
|
|
58
|
+
id: logs
|
|
59
|
+
attributes:
|
|
60
|
+
label: Error output / logs
|
|
61
|
+
description: Paste any relevant CLI output.
|
|
62
|
+
render: shell
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Feature Request
|
|
2
|
+
description: Suggest a new feature or improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for suggesting a feature! Please describe your idea below.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: problem
|
|
12
|
+
attributes:
|
|
13
|
+
label: Problem
|
|
14
|
+
description: What problem does this feature solve? What's missing?
|
|
15
|
+
placeholder: "e.g., I want to allow wildcard patterns in third_party rules, but currently ..."
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: solution
|
|
21
|
+
attributes:
|
|
22
|
+
label: Proposed solution
|
|
23
|
+
description: How do you think this should work?
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: alternatives
|
|
29
|
+
attributes:
|
|
30
|
+
label: Alternatives considered
|
|
31
|
+
description: Any other approaches you've thought about.
|
|
32
|
+
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: context
|
|
35
|
+
attributes:
|
|
36
|
+
label: Additional context
|
|
37
|
+
description: Any other context, examples, or config snippets.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
⚠️ PR Title Convention
|
|
3
|
+
PRs are squash merged, so the PR title becomes the final commit message.
|
|
4
|
+
Please use the following format:
|
|
5
|
+
|
|
6
|
+
<gitmoji> <type>: <Description>
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
✨ feat: Add support for relative imports
|
|
10
|
+
🐛 fix: Use exit code 2 for config file not found
|
|
11
|
+
|
|
12
|
+
See CONTRIBUTING.md for the full list of types.
|
|
13
|
+
-->
|
|
14
|
+
|
|
15
|
+
## What does this PR do?
|
|
16
|
+
|
|
17
|
+
<!-- A brief description of the change. -->
|
|
18
|
+
|
|
19
|
+
## Related issue
|
|
20
|
+
|
|
21
|
+
<!-- Link to the issue this PR addresses, e.g., Closes #123 -->
|
|
22
|
+
|
|
23
|
+
## Checklist
|
|
24
|
+
|
|
25
|
+
- [ ] Tests added / updated
|
|
26
|
+
- [ ] `pdl check` runs without errors on the example config
|
|
27
|
+
- [ ] Documentation updated (if applicable)
|
|
@@ -3,14 +3,18 @@ name: CI
|
|
|
3
3
|
on:
|
|
4
4
|
pull_request:
|
|
5
5
|
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "python_dependency_linter/**"
|
|
8
|
+
- "tests/**"
|
|
9
|
+
- "pyproject.toml"
|
|
6
10
|
|
|
7
11
|
jobs:
|
|
8
12
|
lint:
|
|
9
13
|
runs-on: ubuntu-latest
|
|
10
14
|
steps:
|
|
11
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@v6
|
|
12
16
|
- uses: astral-sh/setup-uv@v4
|
|
13
|
-
- uses: actions/setup-python@
|
|
17
|
+
- uses: actions/setup-python@v6
|
|
14
18
|
with:
|
|
15
19
|
python-version: "3.13"
|
|
16
20
|
- run: uv pip install --system -e ".[dev]"
|
|
@@ -23,9 +27,9 @@ jobs:
|
|
|
23
27
|
matrix:
|
|
24
28
|
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
25
29
|
steps:
|
|
26
|
-
- uses: actions/checkout@
|
|
30
|
+
- uses: actions/checkout@v6
|
|
27
31
|
- uses: astral-sh/setup-uv@v4
|
|
28
|
-
- uses: actions/setup-python@
|
|
32
|
+
- uses: actions/setup-python@v6
|
|
29
33
|
with:
|
|
30
34
|
python-version: ${{ matrix.python-version }}
|
|
31
35
|
- run: uv pip install --system -e ".[dev]"
|
{python_dependency_linter-0.1.0 → python_dependency_linter-0.3.0}/.github/workflows/publish.yaml
RENAMED
|
@@ -11,13 +11,13 @@ jobs:
|
|
|
11
11
|
permissions:
|
|
12
12
|
contents: write
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
14
|
+
- uses: actions/checkout@v6
|
|
15
15
|
with:
|
|
16
16
|
fetch-depth: 0
|
|
17
17
|
- name: Generate full changelog
|
|
18
18
|
uses: orhun/git-cliff-action@v4
|
|
19
19
|
with:
|
|
20
|
-
config:
|
|
20
|
+
config: pyproject.toml
|
|
21
21
|
args: --verbose
|
|
22
22
|
env:
|
|
23
23
|
OUTPUT: CHANGELOG.md
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
id: release_notes
|
|
34
34
|
uses: orhun/git-cliff-action@v4
|
|
35
35
|
with:
|
|
36
|
-
config:
|
|
36
|
+
config: pyproject.toml
|
|
37
37
|
args: --verbose --latest --strip header
|
|
38
38
|
env:
|
|
39
39
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -50,7 +50,7 @@ jobs:
|
|
|
50
50
|
permissions:
|
|
51
51
|
id-token: write
|
|
52
52
|
steps:
|
|
53
|
-
- uses: actions/checkout@
|
|
53
|
+
- uses: actions/checkout@v6
|
|
54
54
|
- uses: actions/setup-python@v5
|
|
55
55
|
with:
|
|
56
56
|
python-version: "3.13"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.2.0] - 2026-03-30
|
|
6
|
+
|
|
7
|
+
### Documentation
|
|
8
|
+
|
|
9
|
+
- Remove design spec and implementation plan docs
|
|
10
|
+
- Add GitHub issue and PR templates
|
|
11
|
+
- Add example for omitted category behavior in allow rules
|
|
12
|
+
- Add architecture examples to README
|
|
13
|
+
- Add pre-commit hook custom options example
|
|
14
|
+
- Expand pyproject.toml examples with multiple rules and deny
|
|
15
|
+
- Add "What It Does" section to README
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
- Support `**` glob pattern for matching nested submodules (#6)
|
|
20
|
+
- Add undocumented features to README
|
|
21
|
+
|
|
22
|
+
### Miscellaneous
|
|
23
|
+
|
|
24
|
+
- Use hatch-vcs for dynamic versioning from git tags
|
|
25
|
+
- Add gitmoji preprocessor to git-cliff config
|
|
26
|
+
- Move git-cliff config from cliff.toml to pyproject.toml
|
|
27
|
+
- Skip CHANGELOG update commits in git-cliff output
|
|
28
|
+
|
|
29
|
+
### Testing
|
|
30
|
+
|
|
31
|
+
- Limit CI to source and test file changes
|
|
32
|
+
|
|
33
|
+
### Build
|
|
34
|
+
|
|
35
|
+
- Bump actions/checkout from 4 to 6 (#3)
|
|
36
|
+
- Bump actions/setup-python from 5 to 6 (#2)
|
|
37
|
+
## [0.1.0] - 2026-03-30
|
|
38
|
+
|
|
39
|
+
### Bug Fixes
|
|
40
|
+
|
|
41
|
+
- Add isort config and fix plan typo
|
|
42
|
+
- Add tomli fallback for Python 3.10 compatibility
|
|
43
|
+
- Add import content to fixture files
|
|
44
|
+
|
|
45
|
+
### CI/CD
|
|
46
|
+
|
|
47
|
+
- Add GitHub Actions for CI, PyPI publish, and Dependabot
|
|
48
|
+
- Add git-cliff changelog generation on release
|
|
49
|
+
- Add GitHub Release creation on tag
|
|
50
|
+
|
|
51
|
+
### Documentation
|
|
52
|
+
|
|
53
|
+
- Add design spec for python-dependency-linter
|
|
54
|
+
- Add implementation plan
|
|
55
|
+
- Add README
|
|
56
|
+
- Add MIT LICENSE
|
|
57
|
+
|
|
58
|
+
### Features
|
|
59
|
+
|
|
60
|
+
- Add config loading for YAML and pyproject.toml
|
|
61
|
+
- Add AST-based import parser
|
|
62
|
+
- Add import resolver for classification
|
|
63
|
+
- Add wildcard matcher and rule merging
|
|
64
|
+
- Add dependency checker with allow/deny logic
|
|
65
|
+
- Add violation reporter
|
|
66
|
+
- Add CLI with check command
|
|
67
|
+
- Add pre-commit hook definition
|
|
68
|
+
|
|
69
|
+
### Miscellaneous
|
|
70
|
+
|
|
71
|
+
- Initialize project scaffolding
|
|
72
|
+
- Add license, readme, and classifiers to pyproject.toml
|
|
73
|
+
- Add .gitignore
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Commit Convention
|
|
4
|
+
|
|
5
|
+
Commit messages must follow [Conventional Commits](https://www.conventionalcommits.org/) with [gitmoji](https://gitmoji.dev/) prefix.
|
|
6
|
+
|
|
7
|
+
### Format
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<gitmoji> <type>: <description>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- The first letter after the colon must be **capitalized**.
|
|
14
|
+
- The description must be in **English**.
|
|
15
|
+
|
|
16
|
+
### Types
|
|
17
|
+
|
|
18
|
+
| Gitmoji | Type | Description |
|
|
19
|
+
|---------|------------|--------------------------|
|
|
20
|
+
| ✨ | `feat` | New feature |
|
|
21
|
+
| 🐛 | `fix` | Bug fix |
|
|
22
|
+
| ♻️ | `refactor` | Code refactoring |
|
|
23
|
+
| 📝 | `docs` | Documentation |
|
|
24
|
+
| ✅ | `test` | Adding or updating tests |
|
|
25
|
+
| 🔧 | `chore` | Maintenance tasks |
|
|
26
|
+
| 👷 | `ci` | CI/CD changes |
|
|
27
|
+
| ⚡ | `perf` | Performance improvement |
|
|
28
|
+
|
|
29
|
+
### Examples
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
✨ feat: Add support for relative imports
|
|
33
|
+
🐛 fix: Use exit code 2 for config file not found
|
|
34
|
+
♻️ refactor: Simplify module resolver logic
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Pull Request Convention
|
|
38
|
+
|
|
39
|
+
- PRs are always **squash merged**, so the PR title becomes the final commit message.
|
|
40
|
+
- PR titles must follow the same format as commit messages (`<gitmoji> <type>: <description>`).
|
|
41
|
+
- PR descriptions must be written in **English**.
|
|
42
|
+
|
|
43
|
+
## Pre-commit Hooks
|
|
44
|
+
|
|
45
|
+
This project uses [pre-commit](https://pre-commit.com/) with [ruff](https://docs.astral.sh/ruff/) for linting and formatting.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Install pre-commit hooks
|
|
49
|
+
pre-commit install
|
|
50
|
+
|
|
51
|
+
# Run manually
|
|
52
|
+
pre-commit run --all-files
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
All commits must pass the pre-commit hooks before being accepted.
|
|
56
|
+
|
|
57
|
+
## Release
|
|
58
|
+
|
|
59
|
+
Releases are automated via GitHub Actions. You only need to create and push a version tag.
|
|
60
|
+
|
|
61
|
+
### Steps
|
|
62
|
+
|
|
63
|
+
1. Calculate the next version based on conventional commits:
|
|
64
|
+
```bash
|
|
65
|
+
uvx git-cliff --bumped-version
|
|
66
|
+
```
|
|
67
|
+
2. Review the commits since the last tag:
|
|
68
|
+
```bash
|
|
69
|
+
git log $(git describe --tags --abbrev=0)..HEAD --oneline
|
|
70
|
+
```
|
|
71
|
+
3. Push the latest commits to `main`:
|
|
72
|
+
```bash
|
|
73
|
+
git push origin main
|
|
74
|
+
```
|
|
75
|
+
4. Create and push the tag:
|
|
76
|
+
```bash
|
|
77
|
+
git tag <version>
|
|
78
|
+
git push origin <version>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The GitHub Actions workflow will then automatically:
|
|
82
|
+
- Generate `CHANGELOG.md` and commit it to `main`
|
|
83
|
+
- Create a GitHub Release with release notes
|
|
84
|
+
- Publish the package to PyPI
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-dependency-linter
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A dependency linter for Python projects
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -27,6 +27,14 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
|
|
28
28
|
A dependency linter for Python projects. Define rules for which modules can depend on what, and catch violations.
|
|
29
29
|
|
|
30
|
+
## What It Does
|
|
31
|
+
|
|
32
|
+
- Define dependency rules between modules using a simple YAML or TOML config
|
|
33
|
+
- Detect imports that violate your rules with a single CLI command
|
|
34
|
+
- Integrate into CI or pre-commit to keep your architecture consistent
|
|
35
|
+
|
|
36
|
+
For Python developers who care about module boundaries and dependency direction — whether you're applying Layered, Hexagonal, Clean Architecture, or your own conventions.
|
|
37
|
+
|
|
30
38
|
## Installation
|
|
31
39
|
|
|
32
40
|
```bash
|
|
@@ -80,8 +88,95 @@ contexts/boards/domain/models.py:9
|
|
|
80
88
|
Found 2 violation(s).
|
|
81
89
|
```
|
|
82
90
|
|
|
91
|
+
## Examples
|
|
92
|
+
|
|
93
|
+
### Layered Architecture
|
|
94
|
+
|
|
95
|
+
Enforce dependency direction: `presentation → application → domain`, where `domain` has no outward dependencies.
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
rules:
|
|
99
|
+
- name: domain-isolation
|
|
100
|
+
modules: my_app.domain
|
|
101
|
+
allow:
|
|
102
|
+
standard_library: ["*"]
|
|
103
|
+
third_party: []
|
|
104
|
+
local: [my_app.domain]
|
|
105
|
+
|
|
106
|
+
- name: application-layer
|
|
107
|
+
modules: my_app.application
|
|
108
|
+
allow:
|
|
109
|
+
standard_library: ["*"]
|
|
110
|
+
third_party: [pydantic]
|
|
111
|
+
local:
|
|
112
|
+
- my_app.application
|
|
113
|
+
- my_app.domain
|
|
114
|
+
|
|
115
|
+
- name: presentation-layer
|
|
116
|
+
modules: my_app.presentation
|
|
117
|
+
allow:
|
|
118
|
+
standard_library: ["*"]
|
|
119
|
+
third_party: [fastapi, pydantic]
|
|
120
|
+
local:
|
|
121
|
+
- my_app.presentation
|
|
122
|
+
- my_app.application
|
|
123
|
+
- my_app.domain
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Hexagonal Architecture
|
|
127
|
+
|
|
128
|
+
Isolate domain from infrastructure. Ports (interfaces) live in domain, adapters depend on domain but not vice versa.
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
rules:
|
|
132
|
+
- name: domain-no-infra
|
|
133
|
+
modules: contexts.*.domain
|
|
134
|
+
allow:
|
|
135
|
+
standard_library: [dataclasses, typing, abc]
|
|
136
|
+
third_party: []
|
|
137
|
+
local: [contexts.*.domain]
|
|
138
|
+
|
|
139
|
+
- name: adapters-depend-on-domain
|
|
140
|
+
modules: contexts.*.adapters
|
|
141
|
+
allow:
|
|
142
|
+
standard_library: ["*"]
|
|
143
|
+
third_party: ["*"]
|
|
144
|
+
local:
|
|
145
|
+
- contexts.*.adapters
|
|
146
|
+
- contexts.*.domain
|
|
147
|
+
```
|
|
148
|
+
|
|
83
149
|
## Configuration
|
|
84
150
|
|
|
151
|
+
### Include / Exclude
|
|
152
|
+
|
|
153
|
+
Control which files are scanned using `include` and `exclude`:
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
include:
|
|
157
|
+
- src
|
|
158
|
+
exclude:
|
|
159
|
+
- src/generated/**
|
|
160
|
+
|
|
161
|
+
rules:
|
|
162
|
+
- name: ...
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
- **No `include` or `exclude`** — All `.py` files under the project root are scanned
|
|
166
|
+
- **`include` only** — Only files matching the given paths are scanned
|
|
167
|
+
- **`exclude` only** — All files except those matching the given paths are scanned
|
|
168
|
+
- **Both** — `include` is applied first, then `exclude` filters within that result
|
|
169
|
+
|
|
170
|
+
Bare directory names (e.g., `src`) and trailing-slash forms (e.g., `src/`) are treated the same as `src/**`.
|
|
171
|
+
|
|
172
|
+
In `pyproject.toml`:
|
|
173
|
+
|
|
174
|
+
```toml
|
|
175
|
+
[tool.python-dependency-linter]
|
|
176
|
+
include = ["src"]
|
|
177
|
+
exclude = ["src/generated/**"]
|
|
178
|
+
```
|
|
179
|
+
|
|
85
180
|
### Rule Structure
|
|
86
181
|
|
|
87
182
|
Each rule has:
|
|
@@ -111,13 +206,25 @@ Dependencies are classified into three categories (per PEP 8):
|
|
|
111
206
|
- `third_party` — Installed packages (`pydantic`, `sqlalchemy`, ...)
|
|
112
207
|
- `local` — Modules in your project
|
|
113
208
|
|
|
209
|
+
Both absolute imports (`from contexts.boards.domain import models`) and relative imports (`from ..domain import models`) are analyzed. Relative imports are resolved to absolute module names based on the file's location.
|
|
210
|
+
|
|
114
211
|
### Behavior
|
|
115
212
|
|
|
116
213
|
- **No rule** — Everything is allowed
|
|
117
214
|
- **`allow` only** — Whitelist mode. Only listed dependencies are allowed
|
|
118
215
|
- **`deny` only** — Blacklist mode. Listed dependencies are denied, rest allowed
|
|
119
216
|
- **`allow` + `deny`** — Allow first, then deny removes exceptions
|
|
120
|
-
- If `allow` exists but a category is omitted, that category allows all
|
|
217
|
+
- If `allow` exists but a category is omitted, that category allows all. For example:
|
|
218
|
+
|
|
219
|
+
```yaml
|
|
220
|
+
rules:
|
|
221
|
+
- name: domain-isolation
|
|
222
|
+
modules: contexts.*.domain
|
|
223
|
+
allow:
|
|
224
|
+
third_party: [pydantic]
|
|
225
|
+
local: [contexts.*.domain]
|
|
226
|
+
# standard_library is omitted → all standard library imports are allowed
|
|
227
|
+
```
|
|
121
228
|
|
|
122
229
|
Use `"*"` to allow all within a category:
|
|
123
230
|
|
|
@@ -134,6 +241,23 @@ allow:
|
|
|
134
241
|
modules: contexts.*.domain # matches contexts.boards.domain, contexts.auth.domain, ...
|
|
135
242
|
```
|
|
136
243
|
|
|
244
|
+
`**` matches one or more levels in dotted module paths:
|
|
245
|
+
|
|
246
|
+
```yaml
|
|
247
|
+
modules: contexts.**.domain # matches contexts.boards.domain, contexts.boards.sub.domain, ...
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Submodule Matching
|
|
251
|
+
|
|
252
|
+
When a pattern is used in `allow` or `deny`, it also matches submodules of the matched module. For example:
|
|
253
|
+
|
|
254
|
+
```yaml
|
|
255
|
+
allow:
|
|
256
|
+
local: [contexts.*.domain]
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
This allows imports of `contexts.boards.domain` as well as its submodules like `contexts.boards.domain.models` or `contexts.boards.domain.entities.metric`.
|
|
260
|
+
|
|
137
261
|
### Rule Merging
|
|
138
262
|
|
|
139
263
|
When multiple rules match a module, they are merged. Specific rules override wildcard rules per field:
|
|
@@ -164,6 +288,22 @@ modules = "contexts.*.domain"
|
|
|
164
288
|
standard_library = ["dataclasses", "typing"]
|
|
165
289
|
third_party = ["pydantic"]
|
|
166
290
|
local = ["contexts.*.domain"]
|
|
291
|
+
|
|
292
|
+
[[tool.python-dependency-linter.rules]]
|
|
293
|
+
name = "application-dependency"
|
|
294
|
+
modules = "contexts.*.application"
|
|
295
|
+
|
|
296
|
+
[tool.python-dependency-linter.rules.allow]
|
|
297
|
+
standard_library = ["*"]
|
|
298
|
+
third_party = ["pydantic"]
|
|
299
|
+
local = ["contexts.*.application", "contexts.*.domain"]
|
|
300
|
+
|
|
301
|
+
[[tool.python-dependency-linter.rules]]
|
|
302
|
+
name = "no-boto-in-domain"
|
|
303
|
+
modules = "contexts.*.domain"
|
|
304
|
+
|
|
305
|
+
[tool.python-dependency-linter.rules.deny]
|
|
306
|
+
third_party = ["boto3"]
|
|
167
307
|
```
|
|
168
308
|
|
|
169
309
|
## CLI
|
|
@@ -183,6 +323,13 @@ Exit codes:
|
|
|
183
323
|
|
|
184
324
|
- `0` — No violations
|
|
185
325
|
- `1` — Violations found
|
|
326
|
+
- `2` — Config file not found
|
|
327
|
+
|
|
328
|
+
If no `--config` is given, the tool looks for `.python-dependency-linter.yaml` in the current directory. If the config file does not exist, the tool prints an error and exits with code `2`:
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
Error: Config file not found: .python-dependency-linter.yaml
|
|
332
|
+
```
|
|
186
333
|
|
|
187
334
|
## Pre-commit
|
|
188
335
|
|
|
@@ -195,6 +342,16 @@ Add to `.pre-commit-config.yaml`:
|
|
|
195
342
|
- id: python-dependency-linter
|
|
196
343
|
```
|
|
197
344
|
|
|
345
|
+
To pass custom options (e.g., a different config file or project root):
|
|
346
|
+
|
|
347
|
+
```yaml
|
|
348
|
+
- repo: https://github.com/heumsi/python-dependency-linter
|
|
349
|
+
rev: v0.1.0
|
|
350
|
+
hooks:
|
|
351
|
+
- id: python-dependency-linter
|
|
352
|
+
args: [--config, custom-config.yaml, --project-root, src]
|
|
353
|
+
```
|
|
354
|
+
|
|
198
355
|
## License
|
|
199
356
|
|
|
200
357
|
MIT
|