python-dependency-linter 0.5.0__tar.gz → 0.5.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.
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/CHANGELOG.md +5 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/PKG-INFO +12 -7
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/README.md +11 -6
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/matcher.py +20 -1
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/test_matcher.py +59 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.claude/skills/commit/SKILL.md +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.claude/skills/release/SKILL.md +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/dependabot.yml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/pull_request_template.md +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/workflows/ci.yaml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/workflows/publish.yaml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.gitignore +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.pre-commit-config.yaml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.pre-commit-hooks.yaml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/CLAUDE.md +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/CONTRIBUTING.md +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/LICENSE +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/pyproject.toml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/checker.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/cli.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/config.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/parser.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/reporter.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/resolver.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_config.yaml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/auth/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/auth/application/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/auth/application/service.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/auth/domain/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/auth/domain/models.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/boards/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/boards/adapters/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/boards/adapters/repository.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/boards/application/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/boards/application/service.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/boards/domain/__init__.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_project/contexts/boards/domain/models.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_pyproject.toml +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/test_checker.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/test_cli.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/test_config.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/test_parser.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/test_reporter.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/test_resolver.py +0 -0
- {python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-dependency-linter
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: A dependency linter for Python projects
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -283,14 +283,19 @@ Named captures coexist with `*` and `**` wildcards. `{name}` always matches exac
|
|
|
283
283
|
|
|
284
284
|
### Submodule Matching
|
|
285
285
|
|
|
286
|
-
When a pattern is used in `allow
|
|
286
|
+
When a pattern is used in `modules`, `allow`, or `deny`, it also matches submodules of the matched module.
|
|
287
|
+
|
|
288
|
+
For example, the following rule applies to `contexts.boards.domain` as well as its submodules like `contexts.boards.domain.models` or `contexts.boards.domain.entities.metric`:
|
|
287
289
|
|
|
288
290
|
```yaml
|
|
289
|
-
|
|
290
|
-
|
|
291
|
+
rules:
|
|
292
|
+
- name: domain-layer
|
|
293
|
+
modules: contexts.*.domain
|
|
294
|
+
allow:
|
|
295
|
+
local: [contexts.*.domain]
|
|
291
296
|
```
|
|
292
297
|
|
|
293
|
-
|
|
298
|
+
> **Note:** `contexts.*.domain` matches the module itself (`__init__.py`) **and** all submodules beneath it, while `contexts.*.domain.**` matches submodules only.
|
|
294
299
|
|
|
295
300
|
### Rule Merging
|
|
296
301
|
|
|
@@ -368,7 +373,7 @@ Add to `.pre-commit-config.yaml`:
|
|
|
368
373
|
|
|
369
374
|
```yaml
|
|
370
375
|
- repo: https://github.com/heumsi/python-dependency-linter
|
|
371
|
-
rev: v0.
|
|
376
|
+
rev: '' # Use the tag you want to point at (e.g., v0.5.0)
|
|
372
377
|
hooks:
|
|
373
378
|
- id: python-dependency-linter
|
|
374
379
|
```
|
|
@@ -377,7 +382,7 @@ To pass custom options (e.g., a different config file):
|
|
|
377
382
|
|
|
378
383
|
```yaml
|
|
379
384
|
- repo: https://github.com/heumsi/python-dependency-linter
|
|
380
|
-
rev: v0.
|
|
385
|
+
rev: '' # Use the tag you want to point at (e.g., v0.5.0)
|
|
381
386
|
hooks:
|
|
382
387
|
- id: python-dependency-linter
|
|
383
388
|
args: [--config, custom-config.yaml]
|
|
@@ -258,14 +258,19 @@ Named captures coexist with `*` and `**` wildcards. `{name}` always matches exac
|
|
|
258
258
|
|
|
259
259
|
### Submodule Matching
|
|
260
260
|
|
|
261
|
-
When a pattern is used in `allow
|
|
261
|
+
When a pattern is used in `modules`, `allow`, or `deny`, it also matches submodules of the matched module.
|
|
262
|
+
|
|
263
|
+
For example, the following rule applies to `contexts.boards.domain` as well as its submodules like `contexts.boards.domain.models` or `contexts.boards.domain.entities.metric`:
|
|
262
264
|
|
|
263
265
|
```yaml
|
|
264
|
-
|
|
265
|
-
|
|
266
|
+
rules:
|
|
267
|
+
- name: domain-layer
|
|
268
|
+
modules: contexts.*.domain
|
|
269
|
+
allow:
|
|
270
|
+
local: [contexts.*.domain]
|
|
266
271
|
```
|
|
267
272
|
|
|
268
|
-
|
|
273
|
+
> **Note:** `contexts.*.domain` matches the module itself (`__init__.py`) **and** all submodules beneath it, while `contexts.*.domain.**` matches submodules only.
|
|
269
274
|
|
|
270
275
|
### Rule Merging
|
|
271
276
|
|
|
@@ -343,7 +348,7 @@ Add to `.pre-commit-config.yaml`:
|
|
|
343
348
|
|
|
344
349
|
```yaml
|
|
345
350
|
- repo: https://github.com/heumsi/python-dependency-linter
|
|
346
|
-
rev: v0.
|
|
351
|
+
rev: '' # Use the tag you want to point at (e.g., v0.5.0)
|
|
347
352
|
hooks:
|
|
348
353
|
- id: python-dependency-linter
|
|
349
354
|
```
|
|
@@ -352,7 +357,7 @@ To pass custom options (e.g., a different config file):
|
|
|
352
357
|
|
|
353
358
|
```yaml
|
|
354
359
|
- repo: https://github.com/heumsi/python-dependency-linter
|
|
355
|
-
rev: v0.
|
|
360
|
+
rev: '' # Use the tag you want to point at (e.g., v0.5.0)
|
|
356
361
|
hooks:
|
|
357
362
|
- id: python-dependency-linter
|
|
358
363
|
args: [--config, custom-config.yaml]
|
|
@@ -59,12 +59,31 @@ def _match_with_captures(
|
|
|
59
59
|
return False
|
|
60
60
|
|
|
61
61
|
|
|
62
|
+
def match_pattern_with_captures_or_submodule(
|
|
63
|
+
pattern: str, module: str
|
|
64
|
+
) -> dict[str, str] | None:
|
|
65
|
+
"""Match pattern exactly or treat module as a submodule of the pattern."""
|
|
66
|
+
captures = match_pattern_with_captures(pattern, module)
|
|
67
|
+
if captures is not None:
|
|
68
|
+
return captures
|
|
69
|
+
# Check if a prefix of the module matches the pattern.
|
|
70
|
+
# e.g. "contexts.*.domain" should match "contexts.boards.domain.models"
|
|
71
|
+
module_parts = module.split(".")
|
|
72
|
+
pattern_parts = pattern.split(".")
|
|
73
|
+
if len(module_parts) > len(pattern_parts):
|
|
74
|
+
prefix = ".".join(module_parts[: len(pattern_parts)])
|
|
75
|
+
captures = match_pattern_with_captures(pattern, prefix)
|
|
76
|
+
if captures is not None:
|
|
77
|
+
return captures
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
62
81
|
def find_matching_rules(
|
|
63
82
|
module: str, rules: list[Rule]
|
|
64
83
|
) -> list[tuple[Rule, dict[str, str]]]:
|
|
65
84
|
result = []
|
|
66
85
|
for r in rules:
|
|
67
|
-
captures =
|
|
86
|
+
captures = match_pattern_with_captures_or_submodule(r.modules, module)
|
|
68
87
|
if captures is not None:
|
|
69
88
|
result.append((r, captures))
|
|
70
89
|
return result
|
|
@@ -214,3 +214,62 @@ def test_capture_after_double_star():
|
|
|
214
214
|
def test_capture_after_double_star_backtrack():
|
|
215
215
|
result = match_pattern_with_captures("**.{x}.end", "a.b.c.end")
|
|
216
216
|
assert result == {"x": "c"}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def test_find_matching_rules_submodule():
|
|
220
|
+
"""modules pattern should match submodules automatically."""
|
|
221
|
+
rules = [
|
|
222
|
+
Rule(
|
|
223
|
+
name="domain-layer",
|
|
224
|
+
modules="contexts.*.domain",
|
|
225
|
+
allow=AllowDeny(local=["contexts.*.domain"]),
|
|
226
|
+
),
|
|
227
|
+
]
|
|
228
|
+
# Exact match still works
|
|
229
|
+
matched = find_matching_rules("contexts.boards.domain", rules)
|
|
230
|
+
assert len(matched) == 1
|
|
231
|
+
assert matched[0][0].name == "domain-layer"
|
|
232
|
+
|
|
233
|
+
# Submodule should also match
|
|
234
|
+
matched = find_matching_rules("contexts.boards.domain.models", rules)
|
|
235
|
+
assert len(matched) == 1
|
|
236
|
+
assert matched[0][0].name == "domain-layer"
|
|
237
|
+
|
|
238
|
+
# Deeper submodule should also match
|
|
239
|
+
matched = find_matching_rules("contexts.boards.domain.entities.metric", rules)
|
|
240
|
+
assert len(matched) == 1
|
|
241
|
+
assert matched[0][0].name == "domain-layer"
|
|
242
|
+
|
|
243
|
+
# Non-matching module should not match
|
|
244
|
+
matched = find_matching_rules("contexts.boards.application.service", rules)
|
|
245
|
+
assert len(matched) == 0
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def test_find_matching_rules_submodule_with_captures():
|
|
249
|
+
"""modules submodule matching should preserve captures."""
|
|
250
|
+
rules = [
|
|
251
|
+
Rule(
|
|
252
|
+
name="domain-layer",
|
|
253
|
+
modules="contexts.{context}.domain",
|
|
254
|
+
allow=AllowDeny(local=["contexts.{context}.domain"]),
|
|
255
|
+
),
|
|
256
|
+
]
|
|
257
|
+
matched = find_matching_rules("contexts.boards.domain.models", rules)
|
|
258
|
+
assert len(matched) == 1
|
|
259
|
+
rule, captures = matched[0]
|
|
260
|
+
assert rule.name == "domain-layer"
|
|
261
|
+
assert captures == {"context": "boards"}
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def test_find_matching_rules_submodule_exact_pattern():
|
|
265
|
+
"""Exact (no wildcard) modules pattern should also match submodules."""
|
|
266
|
+
rules = [
|
|
267
|
+
Rule(
|
|
268
|
+
name="shared",
|
|
269
|
+
modules="src.shared.domain",
|
|
270
|
+
allow=AllowDeny(local=["src.shared.domain"]),
|
|
271
|
+
),
|
|
272
|
+
]
|
|
273
|
+
matched = find_matching_rules("src.shared.domain.entity.user", rules)
|
|
274
|
+
assert len(matched) == 1
|
|
275
|
+
assert matched[0][0].name == "shared"
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.claude/skills/commit/SKILL.md
RENAMED
|
File without changes
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.claude/skills/release/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/ISSUE_TEMPLATE/config.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/pull_request_template.md
RENAMED
|
File without changes
|
|
File without changes
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/.github/workflows/publish.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/cli.py
RENAMED
|
File without changes
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/config.py
RENAMED
|
File without changes
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/python_dependency_linter/parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_dependency_linter-0.5.0 → python_dependency_linter-0.5.1}/tests/fixtures/sample_config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|