Static-analysis enforcement scanners for the 3tears ecosystem (cache primitive contract, underscore-access discipline, codebase conventions, etc.)
Project description
3tears-enforcement
Shared static-analysis enforcement scanners for the 3tears ecosystem.
What this package does
Each module under threetears.enforcement.<domain> ships an AST-based scanner that enforces a single architectural invariant across a Python source tree. Consumer repos import the scanner, inject their per-repo configuration (allowlists, exemption files, src roots), and run it from a thin pytest test class.
This replaces a previous pattern in which the same enforcement test files were vendored verbatim across multiple repos with manual sync requirements. The shared package eliminates duplication and drift while keeping per-repo configuration where it belongs.
Domains
| Module | Invariant enforced |
|---|---|
cache |
Every stateful data surface routes through BaseCollection; no bespoke SQLiteBackend wrappers; no direct pool access to Collection-backed tables; every migration-defined table has a Collection class. |
underscore_access |
Underscore prefix is a stability contract: no cross-module private import, no cross-class protected access, modules with public names have __all__, no subclass shadowing of base private attributes, no __all__ listing private names. |
codebase_conventions |
No bare print(), no stdlib logging.getLogger (use threetears.observe), from __future__ import annotations required, return type annotations required. |
coercion_coverage |
Tool subclasses override execute, never run, preserving the normalize_kwargs → execute input-coercion path. |
dict_state_detection |
No raw dict/OrderedDict persistent state in __init__; use SQLiteBackend (L1) or NATS KV for shared state. |
logger_coverage |
Every production module declares a module-level log = get_logger(__name__) unless explicitly exempt. |
migration_yugabyte_safety |
Migration shapes are yugabyte-safe per threetears.core.data.migrations.enforcement. |
nats_wrapper_usage |
All nats-py imports route through threetears.nats.NatsClient; no direct import nats. |
no_silent_swallow |
Exception handlers must log, re-raise, or carry # NOSILENT: <reason>. |
no_stdlib_logging |
No production module imports stdlib logging directly; use threetears.observe. |
How to use it
Each domain exposes a configuration dataclass and a high-level runner:
# tests/enforcement/test_cache_primitive_usage.py
from pathlib import Path
from threetears.enforcement.cache import CacheEnforcementConfig, run_cache_enforcement
_CONFIG = CacheEnforcementConfig(
repo_root=Path(__file__).parents[2],
allowed_sqlite_construction_sites=frozenset({
"packages/registry/src/threetears/registry/l1_cache.py",
}),
collection_table_allowlist={
"memories": "MemoriesCollection",
# ... per-repo
},
migration_table_allowlist=frozenset({"_schema_migrations"}),
exemptions_path=Path(__file__).parent / "_cache_exemptions.txt",
enforcement_mode_env_var="CACHE_ENFORCEMENT_MODE",
)
class TestCachePrimitiveUsage:
def test_no_bespoke_sqlite_backend_construction(self) -> None:
run_cache_enforcement(_CONFIG, walker="sqlite_construction")
def test_no_bespoke_cache_wrapper_classes(self) -> None:
run_cache_enforcement(_CONFIG, walker="wrapper_class")
def test_no_direct_pool_access_to_collection_tables(self) -> None:
run_cache_enforcement(_CONFIG, walker="pool_access")
def test_all_tables_have_collections(self) -> None:
run_cache_enforcement(_CONFIG, walker="missing_collection")
Per-repo exemption files (e.g., _cache_exemptions.txt) stay in the consumer repo's tests/enforcement/ directory. The package's parse_exemptions_with_rationale reads them at test time.
How to onboard a new repo
- Add
3tears-enforcementas a dev dependency. - For each domain you want to enforce: create a thin shell test file at
tests/enforcement/test_<domain>.pyfollowing the pattern above. Inject your repo's allowlists/exemptions. - Create per-domain exemption files at
tests/enforcement/_<domain>_exemptions.txtif needed. Every exemption requires a preceding# rationale: <specific reason>line. - Run
pytest tests/enforcement/to verify the scanners work against your tree.
How to add a new enforcement domain
- Create
src/threetears/enforcement/<domain>/withwalkers.py,config.py,runner.py, and__init__.py. - Use
common/helpers (ast_helpers,repo_layout,pyproject_discovery,inheritance,exemptions,modes,violations,reports). Do not duplicate scaffolding. - Walkers return
list[Violation]. Configs are frozen dataclasses. Runners orchestrate walker → exemption-application → mode-resolution → report. - Write unit tests in
tests/<domain>/. - Document the domain in this README.
Project details
Release history Release notifications | RSS feed
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 3tears_enforcement-0.15.0.tar.gz.
File metadata
- Download URL: 3tears_enforcement-0.15.0.tar.gz
- Upload date:
- Size: 145.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61d4b6fd2215312d33e3e680011126c1f55528a41966966f976a402df44f4b70
|
|
| MD5 |
f036638fba532e554559c16d2ee3c0d8
|
|
| BLAKE2b-256 |
858269612c53f0d20282647110c0bbf19be1e81e9da246bc92ade7dd2e7a7df6
|
Provenance
The following attestation bundles were made for 3tears_enforcement-0.15.0.tar.gz:
Publisher:
release.yml on pacepace/3tears
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
3tears_enforcement-0.15.0.tar.gz -
Subject digest:
61d4b6fd2215312d33e3e680011126c1f55528a41966966f976a402df44f4b70 - Sigstore transparency entry: 2157046673
- Sigstore integration time:
-
Permalink:
pacepace/3tears@6ba17c2c246cc2768e3deaf3d936c9c03d5b2c4f -
Branch / Tag:
refs/tags/v0.15.0 - Owner: https://github.com/pacepace
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ba17c2c246cc2768e3deaf3d936c9c03d5b2c4f -
Trigger Event:
push
-
Statement type:
File details
Details for the file 3tears_enforcement-0.15.0-py3-none-any.whl.
File metadata
- Download URL: 3tears_enforcement-0.15.0-py3-none-any.whl
- Upload date:
- Size: 137.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4986673141e91d57e66523b7f8fcb865eba7ebb9d3288b4c00602c12d717538
|
|
| MD5 |
d651a85b6bb97b86e9620550dc5fb27d
|
|
| BLAKE2b-256 |
76bd1a589720ab0ee0824090f7d167e006c92094af00f62e668dc7096b219534
|
Provenance
The following attestation bundles were made for 3tears_enforcement-0.15.0-py3-none-any.whl:
Publisher:
release.yml on pacepace/3tears
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
3tears_enforcement-0.15.0-py3-none-any.whl -
Subject digest:
b4986673141e91d57e66523b7f8fcb865eba7ebb9d3288b4c00602c12d717538 - Sigstore transparency entry: 2157050224
- Sigstore integration time:
-
Permalink:
pacepace/3tears@6ba17c2c246cc2768e3deaf3d936c9c03d5b2c4f -
Branch / Tag:
refs/tags/v0.15.0 - Owner: https://github.com/pacepace
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ba17c2c246cc2768e3deaf3d936c9c03d5b2c4f -
Trigger Event:
push
-
Statement type: