From 7207efd35647a1c10e1b566f08b06d8090ceee9c Mon Sep 17 00:00:00 2001 From: heumsi Date: Wed, 1 Apr 2026 02:01:24 +0900 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20Allow=20dot=20(.)=20in=20?= =?UTF-8?q?rule=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand rule name validation regex from [a-zA-Z0-9_-]+ to [a-zA-Z0-9_.-]+ so users can use module-path-style names like `shared.domain`. Closes #27 Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/guide/rules.md | 2 +- docs/reference/config-schema.md | 2 +- python_dependency_linter/config.py | 4 ++-- tests/test_config.py | 6 +++++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/guide/rules.md b/docs/guide/rules.md index aada384..5050a53 100644 --- a/docs/guide/rules.md +++ b/docs/guide/rules.md @@ -21,7 +21,7 @@ The `name` is used in violation output and in `# pdl: ignore` comments. The opti | Field | Required | Description | |-------|----------|-------------| -| `name` | Yes | Unique identifier. Must match `[a-zA-Z0-9_-]+`. Shown in violation output and referenced in `# pdl: ignore` comments | +| `name` | Yes | Unique identifier. Must match `[a-zA-Z0-9_.-]+`. Shown in violation output and referenced in `# pdl: ignore` comments | | `modules` | Yes | Module pattern to apply the rule to. Supports `*`, `**`, and `{name}` captures (see [Patterns](#patterns)) | | `description` | No | Human-readable description shown in violation output | | `allow` | No | Whitelist of allowed dependencies (see [Allow / Deny](#allow-deny)) | diff --git a/docs/reference/config-schema.md b/docs/reference/config-schema.md index fccee53..5c3819b 100644 --- a/docs/reference/config-schema.md +++ b/docs/reference/config-schema.md @@ -14,7 +14,7 @@ Complete reference for all configuration fields. | Field | Type | Required | Default | Description | |-------|------|----------|---------|-------------| -| `name` | str | Yes | — | Rule identifier, shown in violation output. Must match `[a-zA-Z0-9_-]+` | +| `name` | str | Yes | — | Rule identifier, shown in violation output. Must match `[a-zA-Z0-9_.-]+` | | `modules` | str | Yes | — | Module pattern to apply the rule to. Supports `*`, `**`, and `{name}` captures | | `description` | str | No | `null` | Human-readable description shown in violation output | | `allow` | [DependencyFilter](#dependencyfilter) | No | `null` | Whitelist of allowed dependencies | diff --git a/python_dependency_linter/config.py b/python_dependency_linter/config.py index 61916f0..72418e3 100644 --- a/python_dependency_linter/config.py +++ b/python_dependency_linter/config.py @@ -40,7 +40,7 @@ def _parse_allow_deny(data: dict | None) -> AllowDeny | None: ) -_RULE_NAME_PATTERN = re.compile(r"^[a-zA-Z0-9_-]+$") +_RULE_NAME_PATTERN = re.compile(r"^[a-zA-Z0-9_.\-]+$") def _parse_rules(rules_data: list[dict]) -> list[Rule]: @@ -49,7 +49,7 @@ def _parse_rules(rules_data: list[dict]) -> list[Rule]: name = r["name"] if not _RULE_NAME_PATTERN.match(name): raise ValueError( - f"Invalid rule name '{name}'. Rule names must match [a-zA-Z0-9_-]+" + f"Invalid rule name '{name}'. Rule names must match [a-zA-Z0-9_.-]+" ) rules.append( Rule( diff --git a/tests/test_config.py b/tests/test_config.py index 2042489..f3328f4 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -141,11 +141,15 @@ def test_valid_rule_names(tmp_path): modules: src.* - name: rule1 modules: src.* + - name: shared.domain + modules: src.* + - name: context.adapters.inbound + modules: src.* """ config_file = tmp_path / "config.yaml" config_file.write_text(config_content) config = load_config(config_file) - assert len(config.rules) == 3 + assert len(config.rules) == 5 def test_invalid_rule_name_with_space(tmp_path):