Consolidated strict Python linting and static analysis tools - AST-based DTO discipline, facade-ban enforcement, and complexity metrics.
Project description
strict-suite
AST-based linter for Python DTO discipline and facade-ban enforcement. Consolidated strict Python linting and static analysis tools with complexity metrics.
Consolidated from strict-module 0.5.0. This monorepo consolidates the strict-module package and related linting infrastructure. Backward-compatible CLI entry points (strict-module and dto-strict) are preserved.
Python only. The strict-component (npm/TypeScript) stays in its own repo. This distribution is Python 3.11+ only.
Overview
Data Transfer Objects (DTOs) and facade discipline are critical for clean API boundaries, especially in regulated environments (healthcare, compliance, financial systems). stricts enforces these patterns via static AST analysis, with 6 focused rules:
- R001 (HIGH): Detect
Dict[str, Any]or baredict/list/tuplein service-layer function signatures. - R002 (MEDIUM): Flag inline dict literals with 3+ string keys; exception tags can require justification.
- R003 (MEDIUM): Flag
repr=Falsein dataclasses (canonical: plain@dataclass(frozen=True, slots=True)). - R004 (HIGH): Demand exception tags on module-level functions (e.g.,
# facade - celery schedule). - R005 (LOW): Encourage validators to use
DTO.from_dict()pattern. - R006 (HIGH): Detect
typing.Anyin function signatures (parameters and return types).
All rules are configurable; violations can be disabled, severity overridden, or paths scoped.
Install
pip install strict-suite
Or with optional development dependencies:
pip install strict-suite[dev]
Both CLI entry points (strict-module and dto-strict) are available post-install.
Quick Start
Basic CLI Usage
# Lint a single file
strict-module apps/compliance/services.py
# Lint a directory
strict-module apps/
# Output as GitHub Actions annotations
strict-module apps/ --format github
# Output as JSON
strict-module apps/ --format json
# Use the compat alias
dto-strict apps/
Run-Verified Example
Create a test file example.py with conformant code:
from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class UserDTO:
"""User data transfer object."""
user_id: int
email: str
class UserService:
"""Service to process users."""
def process_user(self, user: UserDTO) -> None:
"""Process a user."""
print(f"Processing {user.email}")
Then lint it:
$ strict-module example.py
# (no output = clean)
Now create a violating example. Save this as apps/test/services/bad_user.py:
from typing import Any
class UserService:
def process_user(self, config: dict[str, Any]) -> None: # R001: Dict[str, Any] in signature
"""Process a user."""
return config.get("user_id")
Running the linter (from the repo root):
$ strict-module apps/test/services/bad_user.py
apps/test/services/bad_user.py:4: R001 Dict[str, Any] in signature: process_user
apps/test/services/bad_user.py:4: R006 typing.Any in parameter: process_user
All Rules Demonstrated
R002 (inline dict literals with 3+ keys):
# violation
def example():
data = {"key1": "val1", "key2": "val2", "key3": "val3"}
R003 (anti-canonical repr=False on dataclass):
# violation
from dataclasses import dataclass
@dataclass(repr=False)
class MyDTO:
value: int
R004 (module-level function without exception tag):
# violation (in a non-conftest file)
def process_data(item):
return item["id"]
R007 (pytest fixtures outside conftest.py):
# violation
import pytest
@pytest.fixture
def my_fixture():
return "value"
R008 (bare module-level test functions):
# violation
def test_something():
assert True
LOC Cap Enforcement
Check lines-of-code limits:
$ strict-module loc-cap src/
src/long_module.py: soft-target 500 exceeded (523 lines)
src/another.py: hard-cap 694 exceeded (750 lines) FAIL
Generate baseline:
$ strict-module loc-cap src/ --generate-baseline > .loc-cap-baseline.txt
Using Both CLI Entry Points
Both strict-module and dto-strict are equivalent aliases:
strict-module apps/
dto-strict apps/
Configuration
Configuration lives in pyproject.toml:
[tool.strict-module]
service_paths = ["apps/*/services/*.py", "**/services/*.py"]
dto_paths = ["**/dtos.py", "**/dtos/*.py"]
exception_tags = [
"facade - celery schedule",
"FRAMEWORK",
"aws-boundary"
]
disabled_rules = []
severity_overrides = {}
- service_paths: Glob patterns for files to lint with R001 (strict mode).
- dto_paths: Glob patterns for files expected to contain DTO definitions.
- exception_tags: Recognized justification tags for module-level functions (R004 and R009). Example:
aws-boundaryexempts a function from the module-level function rules. - disabled_rules: List of rule IDs to disable (e.g., ["R005"]).
- severity_overrides: Dict mapping rule IDs to override severity (e.g., {"R002": "HIGH", "R011": "INFO"}).
Backward compatibility: [tool.strict-module] config and .strict-module-baseline.json baseline files are supported.
Suppressing Violations
Use # noqa comments to suppress violations on specific lines. Supported forms:
-
Bare
# noqa: Suppress any rule on that line.x = {1: 2, 3: 4, 5: 6} # noqa
-
Rule-specific
# noqa: R006: Suppress a single rule by ID.def process(x: Any) -> None: # noqa: R006 pass
-
Namespaced
# noqa: strict-module-R006: Use the ruff-external-friendly namespaced form (recommended when running ruff alongside).def process(x: Any) -> None: # noqa: strict-module-R006 pass
-
Multiple rules
# noqa: R006, R011: Suppress multiple rules on one line.def process(x: Any) -> None: # noqa: R006, R011 pass
Special note on R014 (kwarg grouping): R014 findings report at the offending kwarg line, but noqa suppression only works on the line where the call begins. Place the noqa comment on the CALL line, not the kwarg line:
self.log_event( # noqa: R014
const.LOG_EVENT_SUCCESS, a=1, b=2, c=3, d=4,
)
When using ruff in parallel, declare [tool.ruff.lint] external = ["strict-module"] in pyproject.toml to prevent ruff from warning on the external rule codes.
Public API
The package exports the following public symbols:
__version__: Package version string (e.g., "0.1.0")DtoStrictLinter: Main linter class for running AST analysisRule: Rule definition dataclassRuleSeverity: Enum for rule severity levels (HIGH, MEDIUM, LOW)
Example usage:
from strict_module import DtoStrictLinter, Rule, RuleSeverity, __version__
print(f"strict-suite {__version__}")
linter = DtoStrictLinter()
violations = linter.lint_file("mymodule.py")
for v in violations:
print(f"{v.rule_id} ({v.severity.value}): {v.message}")
Documentation
Full documentation, including rule details, configuration options, and integration guides, is available in the docs/ directory.
Historical changelog: see CHANGELOG-history.md for strict-module v0.1.0 through v0.5.0 release history.
Development
Install dev dependencies:
pip install -e ".[dev]"
Run tests:
python3.12 -m pytest strict_module/tests/ -v
Run the self-lint check:
strict-module strict_module/ --format text
dto-strict strict_module/
Run format and style checks:
ruff check strict_module/
ruff format --check strict_module/
Run LOC cap check:
strict-module loc-cap strict_module/
License
Apache License 2.0. See LICENSE for full text.
Contributing
Contributions are welcome. Please ensure:
- All tests pass.
- Code follows the project's linting rules (run
strict-moduleon your changes). - Commit messages are clear and describe the change.
- No AI attribution in commit messages.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file strict_suite-0.5.0.tar.gz.
File metadata
- Download URL: strict_suite-0.5.0.tar.gz
- Upload date:
- Size: 120.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
974e74cafcb2f1f833b712998bdad5f23c7d4452e3981d2f97988440e2eee7b3
|
|
| MD5 |
3c78f23567ea85ff66bf6fb356b16e5a
|
|
| BLAKE2b-256 |
18bbf54c9c1fb044edcf1c71288637cd631bdd8624af5ad8a0b64b66a5c39ede
|
Provenance
The following attestation bundles were made for strict_suite-0.5.0.tar.gz:
Publisher:
publish.yml on jekhator/strict-suite
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
strict_suite-0.5.0.tar.gz -
Subject digest:
974e74cafcb2f1f833b712998bdad5f23c7d4452e3981d2f97988440e2eee7b3 - Sigstore transparency entry: 2256873065
- Sigstore integration time:
-
Permalink:
jekhator/strict-suite@d5dd1da3f76bfc247c0a829b35dc3e4b0f1df6cc -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/jekhator
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d5dd1da3f76bfc247c0a829b35dc3e4b0f1df6cc -
Trigger Event:
release
-
Statement type:
File details
Details for the file strict_suite-0.5.0-py3-none-any.whl.
File metadata
- Download URL: strict_suite-0.5.0-py3-none-any.whl
- Upload date:
- Size: 42.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb4d61857c0a631fe0f4bcceaa04bbaa97f64633d7a03bbb33cf41968a8f87a7
|
|
| MD5 |
1adf5603599b0582c5ef5490e9dc1bf9
|
|
| BLAKE2b-256 |
c4029616fa13e9d5486e306bb2ef613c67ce342b0da47507d01c620656441b55
|
Provenance
The following attestation bundles were made for strict_suite-0.5.0-py3-none-any.whl:
Publisher:
publish.yml on jekhator/strict-suite
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
strict_suite-0.5.0-py3-none-any.whl -
Subject digest:
cb4d61857c0a631fe0f4bcceaa04bbaa97f64633d7a03bbb33cf41968a8f87a7 - Sigstore transparency entry: 2256873076
- Sigstore integration time:
-
Permalink:
jekhator/strict-suite@d5dd1da3f76bfc247c0a829b35dc3e4b0f1df6cc -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/jekhator
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d5dd1da3f76bfc247c0a829b35dc3e4b0f1df6cc -
Trigger Event:
release
-
Statement type: