From 72ce55ba845f76bd9e534f7ff940f3e3b2890751 Mon Sep 17 00:00:00 2001 From: Youcef Kadri Date: Fri, 1 May 2026 15:31:00 +1000 Subject: [PATCH 1/4] Use Literal types for query names (immutable registry keys) Changed all 5 query classes to use Literal types for their name field: - DeadCodeQuery: Literal["find-dead-code"] - ModuleCentralityQuery: Literal["analyze-module-centrality"] - CriticalFunctionsQuery: Literal["find-critical-functions"] - CallComplexityQuery: Literal["analyze-call-complexity"] - CircularDependenciesQuery: Literal["detect-circular-dependencies"] Benefits: - Type checker enforces exact string values - IDE autocomplete shows valid query names - Prevents accidental name modifications at runtime - Better registry integrity (names are keys) All 27 query tests passing. Co-Authored-By: Claude Sonnet 4.5 --- src/mapper/query_system/queries/call_complexity.py | 4 ++-- src/mapper/query_system/queries/circular_dependencies.py | 4 ++-- src/mapper/query_system/queries/critical_functions.py | 4 ++-- src/mapper/query_system/queries/dead_code.py | 4 ++-- src/mapper/query_system/queries/module_centrality.py | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mapper/query_system/queries/call_complexity.py b/src/mapper/query_system/queries/call_complexity.py index 60db052..c0a475d 100644 --- a/src/mapper/query_system/queries/call_complexity.py +++ b/src/mapper/query_system/queries/call_complexity.py @@ -1,6 +1,6 @@ """Call complexity query - functions with deep call chains.""" -from typing import Any +from typing import Any, Literal import attrs @@ -32,7 +32,7 @@ class CallComplexityQuery(Query): # Metadata # ------------------------------------------------------------------------- - name: str = "analyze-call-complexity" + name: Literal["analyze-call-complexity"] = "analyze-call-complexity" description: str = "Find functions with deep call chains" group: QueryGroup = QueryGroup.RISK columns: list[str] = attrs.field(factory=lambda: ["Severity", "Function", "Max Depth"]) diff --git a/src/mapper/query_system/queries/circular_dependencies.py b/src/mapper/query_system/queries/circular_dependencies.py index 5e218aa..8777e92 100644 --- a/src/mapper/query_system/queries/circular_dependencies.py +++ b/src/mapper/query_system/queries/circular_dependencies.py @@ -1,6 +1,6 @@ """Circular dependencies query - module import cycles.""" -from typing import Any +from typing import Any, Literal import attrs @@ -31,7 +31,7 @@ class CircularDependenciesQuery(Query): # Metadata # ------------------------------------------------------------------------- - name: str = "detect-circular-dependencies" + name: Literal["detect-circular-dependencies"] = "detect-circular-dependencies" description: str = "Find circular dependencies in module imports" group: QueryGroup = QueryGroup.RISK columns: list[str] = attrs.field(factory=lambda: ["Severity", "Cycle", "Length"]) diff --git a/src/mapper/query_system/queries/critical_functions.py b/src/mapper/query_system/queries/critical_functions.py index 7db3670..6303fab 100644 --- a/src/mapper/query_system/queries/critical_functions.py +++ b/src/mapper/query_system/queries/critical_functions.py @@ -1,6 +1,6 @@ """Critical functions query - find most-called functions.""" -from typing import Any +from typing import Any, Literal import attrs @@ -26,7 +26,7 @@ class CriticalFunctionsQuery(Query): # Metadata # ------------------------------------------------------------------------- - name: str = "find-critical-functions" + name: Literal["find-critical-functions"] = "find-critical-functions" description: str = "Find most-called functions" group: QueryGroup = QueryGroup.CRITICAL columns: list[str] = attrs.field(factory=lambda: ["Severity", "Function", "Callers", "Risk"]) diff --git a/src/mapper/query_system/queries/dead_code.py b/src/mapper/query_system/queries/dead_code.py index 7c7d46f..71c5657 100644 --- a/src/mapper/query_system/queries/dead_code.py +++ b/src/mapper/query_system/queries/dead_code.py @@ -1,6 +1,6 @@ """Find dead code query - unused functions and classes.""" -from typing import Any +from typing import Any, Literal import attrs @@ -24,7 +24,7 @@ class DeadCodeQuery(Query): # Metadata # ------------------------------------------------------------------------- - name: str = "find-dead-code" + name: Literal["find-dead-code"] = "find-dead-code" description: str = "Find unused functions and classes" group: QueryGroup = QueryGroup.RISK columns: list[str] = attrs.field(factory=lambda: ["Severity", "FQN", "Type", "Public"]) diff --git a/src/mapper/query_system/queries/module_centrality.py b/src/mapper/query_system/queries/module_centrality.py index e6b77c8..eab0d6d 100644 --- a/src/mapper/query_system/queries/module_centrality.py +++ b/src/mapper/query_system/queries/module_centrality.py @@ -1,6 +1,6 @@ """Module centrality query - find most depended-on modules.""" -from typing import Any +from typing import Any, Literal import attrs @@ -25,7 +25,7 @@ class ModuleCentralityQuery(Query): # Metadata # ------------------------------------------------------------------------- - name: str = "analyze-module-centrality" + name: Literal["analyze-module-centrality"] = "analyze-module-centrality" description: str = "Find most depended-on modules" group: QueryGroup = QueryGroup.CRITICAL columns: list[str] = attrs.field(factory=lambda: ["Severity", "Module", "Dependents", "Risk"]) From 2c1640788fcc2c5ecd0044215509dc27779096d7 Mon Sep 17 00:00:00 2001 From: Youcef Kadri Date: Fri, 1 May 2026 15:31:37 +1000 Subject: [PATCH 2/4] Use Literal types for quality rule names (immutable registry keys) Changed all 3 quality rule classes to use Literal types for their name field: - TypeCoverageRule: Literal["type-coverage"] - DocstringCoverageRule: Literal["docstring-coverage"] - ParamComplexityRule: Literal["param-complexity"] Benefits: - Type checker enforces exact string values - IDE autocomplete shows valid rule names - Prevents accidental name modifications at runtime - Better registry integrity (names are keys) - Consistent with query system All 85 quality tests passing. Co-Authored-By: Claude Sonnet 4.5 --- src/mapper/quality/rules/docstring_coverage.py | 3 ++- src/mapper/quality/rules/param_complexity.py | 3 ++- src/mapper/quality/rules/type_coverage.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mapper/quality/rules/docstring_coverage.py b/src/mapper/quality/rules/docstring_coverage.py index 40d5f78..d6828e1 100644 --- a/src/mapper/quality/rules/docstring_coverage.py +++ b/src/mapper/quality/rules/docstring_coverage.py @@ -1,6 +1,7 @@ """Docstring coverage quality rule implementation.""" import fnmatch +from typing import Literal import attrs @@ -12,7 +13,7 @@ class DocstringCoverageRule(models.QualityRule): """Quality rule for enforcing docstring coverage on public functions.""" - name: str = "docstring-coverage" + name: Literal["docstring-coverage"] = "docstring-coverage" description: str = "Enforce docstring coverage on public functions" def is_enabled(self, config: models.QualityConfig) -> bool: diff --git a/src/mapper/quality/rules/param_complexity.py b/src/mapper/quality/rules/param_complexity.py index f23d8e5..faeca93 100644 --- a/src/mapper/quality/rules/param_complexity.py +++ b/src/mapper/quality/rules/param_complexity.py @@ -1,6 +1,7 @@ """Parameter complexity quality rule implementation.""" import fnmatch +from typing import Literal import attrs @@ -12,7 +13,7 @@ class ParamComplexityRule(models.QualityRule): """Quality rule for enforcing parameter count limits on functions.""" - name: str = "param-complexity" + name: Literal["param-complexity"] = "param-complexity" description: str = "Enforce parameter count limits on functions" def is_enabled(self, config: models.QualityConfig) -> bool: diff --git a/src/mapper/quality/rules/type_coverage.py b/src/mapper/quality/rules/type_coverage.py index b12a2d1..01c9fc2 100644 --- a/src/mapper/quality/rules/type_coverage.py +++ b/src/mapper/quality/rules/type_coverage.py @@ -1,6 +1,7 @@ """Type coverage quality rule implementation.""" import fnmatch +from typing import Literal import attrs @@ -12,7 +13,7 @@ class TypeCoverageRule(models.QualityRule): """Quality rule for enforcing type hint coverage on public functions.""" - name: str = "type-coverage" + name: Literal["type-coverage"] = "type-coverage" description: str = "Enforce type hint coverage on public functions" def is_enabled(self, config: models.QualityConfig) -> bool: From 963446549c7d30d993c2421ac67f10f3d3ef2327 Mon Sep 17 00:00:00 2001 From: Youcef Kadri Date: Fri, 1 May 2026 15:33:29 +1000 Subject: [PATCH 3/4] Update CHANGELOG for v0.8.3 --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3afad46..ecdbedf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.8.3] - 2026-04-14 + +### Changed +- **Immutable registry keys with Literal types** - Type-safe name fields for queries and quality rules + - Query names now use `Literal["exact-name"]` instead of `str` for all 5 built-in queries + - `find-dead-code`, `analyze-module-centrality`, `find-critical-functions`, `analyze-call-complexity`, `detect-circular-dependencies` + - Quality rule names now use `Literal["exact-name"]` instead of `str` for all 3 built-in rules + - `type-coverage`, `docstring-coverage`, `param-complexity` + - Benefits: + - **Type safety**: Typos in registry lookups caught at type-check time instead of runtime + - **IDE autocomplete**: IDEs can suggest valid query/rule names from Literal type + - **Immutability**: Frozen attrs classes with Literal types prevent runtime name modifications + - **Self-documenting**: Type signature shows exact valid values + - No behavior changes - purely a type safety improvement + - All 289 tests passing + ## [0.8.2] - 2026-04-14 ### Added From 0d2748076f8c0cec5675c5185331d7091035f2f5 Mon Sep 17 00:00:00 2001 From: Youcef Kadri Date: Fri, 1 May 2026 15:33:32 +1000 Subject: [PATCH 4/4] =?UTF-8?q?Bump=20version:=200.8.2=20=E2=86=92=200.8.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 2 +- README.md | 2 +- pyproject.toml | 4 ++-- src/mapper/__init__.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e9cd731..c07ded7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -423,4 +423,4 @@ Review these documents to understand patterns and best practices: --- **Last Updated**: 2026-04-14 -**Current Version**: 0.8.2 +**Current Version**: 0.8.3 diff --git a/README.md b/README.md index 4ca2c4a..0164d05 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Mapper (Application Mapper) -![Version](https://img.shields.io/badge/version-0.8.2-blue.svg) +![Version](https://img.shields.io/badge/version-0.8.3-blue.svg) ![Tests](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/ydkadri/9501806ed5eac873dd324bc606c6dd79/raw/mapper-tests.json&cacheSeconds=300) ![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/ydkadri/9501806ed5eac873dd324bc606c6dd79/raw/mapper-coverage.json&cacheSeconds=300) ![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg) diff --git a/pyproject.toml b/pyproject.toml index 449584e..7b6854e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "mapper" -version = "0.8.2" +version = "0.8.3" description = "Mapper (Application Mapper) - AST-based Python code analyzer with Neo4j graph storage" readme = "README.md" requires-python = ">=3.10" @@ -93,7 +93,7 @@ addopts = [ testpaths = ["tests"] [tool.bumpversion] -current_version = "0.8.2" +current_version = "0.8.3" parse = "(?P\\d+)\\.(?P\\d+)\\.(?P\\d+)" serialize = ["{major}.{minor}.{patch}"] search = "{current_version}" diff --git a/src/mapper/__init__.py b/src/mapper/__init__.py index 9e5ea71..4184f32 100644 --- a/src/mapper/__init__.py +++ b/src/mapper/__init__.py @@ -3,7 +3,7 @@ # Public modules for programmatic access from mapper import analyser, graph, graph_loader -__version__ = "0.8.2" +__version__ = "0.8.3" __all__ = [ # Version