pycodegate 0.1.0__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.
- pycodegate-0.1.0/.github/workflows/ci.yml +45 -0
- pycodegate-0.1.0/.github/workflows/publish.yml +16 -0
- pycodegate-0.1.0/.gitignore +17 -0
- pycodegate-0.1.0/AGENTS.md +78 -0
- pycodegate-0.1.0/LICENSE +21 -0
- pycodegate-0.1.0/PKG-INFO +357 -0
- pycodegate-0.1.0/README.md +323 -0
- pycodegate-0.1.0/docs/superpowers/plans/2026-03-22-python-doctor.md +3305 -0
- pycodegate-0.1.0/pyproject.toml +74 -0
- pycodegate-0.1.0/skills/py-gate/SKILL.md +26 -0
- pycodegate-0.1.0/src/pycodegate/__init__.py +3 -0
- pycodegate-0.1.0/src/pycodegate/_compat.py +15 -0
- pycodegate-0.1.0/src/pycodegate/api.py +26 -0
- pycodegate-0.1.0/src/pycodegate/cli.py +131 -0
- pycodegate-0.1.0/src/pycodegate/config.py +81 -0
- pycodegate-0.1.0/src/pycodegate/constants.py +32 -0
- pycodegate-0.1.0/src/pycodegate/discover.py +114 -0
- pycodegate-0.1.0/src/pycodegate/output.py +270 -0
- pycodegate-0.1.0/src/pycodegate/profile.py +107 -0
- pycodegate-0.1.0/src/pycodegate/rules/__init__.py +38 -0
- pycodegate-0.1.0/src/pycodegate/rules/architecture.py +121 -0
- pycodegate-0.1.0/src/pycodegate/rules/base.py +23 -0
- pycodegate-0.1.0/src/pycodegate/rules/complexity.py +87 -0
- pycodegate-0.1.0/src/pycodegate/rules/correctness.py +131 -0
- pycodegate-0.1.0/src/pycodegate/rules/dead_code.py +58 -0
- pycodegate-0.1.0/src/pycodegate/rules/dependencies.py +107 -0
- pycodegate-0.1.0/src/pycodegate/rules/django.py +144 -0
- pycodegate-0.1.0/src/pycodegate/rules/fastapi.py +70 -0
- pycodegate-0.1.0/src/pycodegate/rules/flask.py +115 -0
- pycodegate-0.1.0/src/pycodegate/rules/imports.py +96 -0
- pycodegate-0.1.0/src/pycodegate/rules/performance.py +104 -0
- pycodegate-0.1.0/src/pycodegate/rules/security.py +167 -0
- pycodegate-0.1.0/src/pycodegate/rules/structure.py +242 -0
- pycodegate-0.1.0/src/pycodegate/scan.py +201 -0
- pycodegate-0.1.0/src/pycodegate/score.py +69 -0
- pycodegate-0.1.0/src/pycodegate/types.py +65 -0
- pycodegate-0.1.0/src/pycodegate/utils/__init__.py +1 -0
- pycodegate-0.1.0/src/pycodegate/utils/ast_helpers.py +19 -0
- pycodegate-0.1.0/src/pycodegate/utils/badge.py +51 -0
- pycodegate-0.1.0/src/pycodegate/utils/diff.py +24 -0
- pycodegate-0.1.0/src/pycodegate/utils/file_discovery.py +62 -0
- pycodegate-0.1.0/src/pycodegate/utils/fixer.py +32 -0
- pycodegate-0.1.0/src/pycodegate/utils/precommit.py +48 -0
- pycodegate-0.1.0/tests/conftest.py +1 -0
- pycodegate-0.1.0/tests/fixtures/basic_python/app.py +24 -0
- pycodegate-0.1.0/tests/fixtures/clean_project/app.py +19 -0
- pycodegate-0.1.0/tests/rules/__init__.py +0 -0
- pycodegate-0.1.0/tests/rules/test_architecture.py +52 -0
- pycodegate-0.1.0/tests/rules/test_complexity.py +92 -0
- pycodegate-0.1.0/tests/rules/test_correctness.py +61 -0
- pycodegate-0.1.0/tests/rules/test_dead_code.py +30 -0
- pycodegate-0.1.0/tests/rules/test_dependencies.py +60 -0
- pycodegate-0.1.0/tests/rules/test_django.py +39 -0
- pycodegate-0.1.0/tests/rules/test_fastapi.py +57 -0
- pycodegate-0.1.0/tests/rules/test_flask.py +36 -0
- pycodegate-0.1.0/tests/rules/test_imports.py +49 -0
- pycodegate-0.1.0/tests/rules/test_performance.py +47 -0
- pycodegate-0.1.0/tests/rules/test_security.py +59 -0
- pycodegate-0.1.0/tests/rules/test_structure.py +114 -0
- pycodegate-0.1.0/tests/test_cli.py +125 -0
- pycodegate-0.1.0/tests/test_config.py +100 -0
- pycodegate-0.1.0/tests/test_discover.py +104 -0
- pycodegate-0.1.0/tests/test_fixer.py +33 -0
- pycodegate-0.1.0/tests/test_integration.py +30 -0
- pycodegate-0.1.0/tests/test_output.py +286 -0
- pycodegate-0.1.0/tests/test_profile.py +170 -0
- pycodegate-0.1.0/tests/test_scan.py +51 -0
- pycodegate-0.1.0/tests/test_score.py +145 -0
- pycodegate-0.1.0/tests/test_types.py +56 -0
- pycodegate-0.1.0/uv.lock +386 -0
- pycodegate-0.1.0/whitelist.py +14 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v5
|
|
18
|
+
- uses: astral-sh/setup-uv@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
run: uv python install ${{ matrix.python-version }}
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: uv sync --all-extras
|
|
25
|
+
|
|
26
|
+
- name: Run tests
|
|
27
|
+
run: uv run pytest --tb=short -q
|
|
28
|
+
|
|
29
|
+
- name: Run py-gate on itself
|
|
30
|
+
run: uv run py-gate . --fail-on error
|
|
31
|
+
|
|
32
|
+
lint:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v5
|
|
36
|
+
- uses: astral-sh/setup-uv@v4
|
|
37
|
+
|
|
38
|
+
- name: Install dependencies
|
|
39
|
+
run: uv sync --all-extras
|
|
40
|
+
|
|
41
|
+
- name: Ruff check
|
|
42
|
+
run: uv run ruff check .
|
|
43
|
+
|
|
44
|
+
- name: Ruff format check
|
|
45
|
+
run: uv run ruff format --check .
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
publish:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
permissions:
|
|
10
|
+
id-token: write
|
|
11
|
+
environment: pypi
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: astral-sh/setup-uv@v5
|
|
15
|
+
- run: uv build
|
|
16
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
py-gate is a Python code quality gate that produces a 0–100 health score. It detects your framework, runs parallel lint and dead-code analysis across 40+ rules, and reports findings by severity so you always know what to fix first.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uvx py-gate . --json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## For AI Agents
|
|
14
|
+
|
|
15
|
+
Run `py-gate . --json` after modifying Python files. Fix findings with severity `"error"` first (security, correctness). Re-run to verify the score improved. Target: **80+**.
|
|
16
|
+
|
|
17
|
+
The JSON output includes the score, label, per-diagnostic severity and file location, and detected project context (framework, Python version, package manager).
|
|
18
|
+
|
|
19
|
+
## General Rules
|
|
20
|
+
|
|
21
|
+
- MUST: Use `uv` for all Python operations. `uv run` to execute, `uv sync` to install.
|
|
22
|
+
- MUST: Follow existing code patterns — AST-based rule checks extending `BaseRules`.
|
|
23
|
+
- MUST: Keep all types in `src/pycodegate/types.py`.
|
|
24
|
+
- MUST: Use dataclasses (frozen) for data containers.
|
|
25
|
+
- MUST: Never comment unless absolutely necessary.
|
|
26
|
+
- If the code is a hack, prefix with `# HACK: reason`
|
|
27
|
+
- MUST: Use snake_case for files and variables.
|
|
28
|
+
- MUST: Use descriptive names (avoid shorthands or 1-2 character names).
|
|
29
|
+
- MUST: Do not use `type: ignore` unless absolutely necessary.
|
|
30
|
+
- MUST: Remove unused code and don't repeat yourself.
|
|
31
|
+
- MUST: Put all magic numbers in `constants.py` using `SCREAMING_SNAKE_CASE`.
|
|
32
|
+
- MUST: Put small, focused utility functions in `utils/` with one utility per file.
|
|
33
|
+
- MUST: Use early returns and guard clauses to reduce nesting depth below 5.
|
|
34
|
+
- MUST: Keep functions under 50 lines.
|
|
35
|
+
|
|
36
|
+
## Development
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uv run pytest -q # run all tests
|
|
40
|
+
uv run ruff check . && uv run ruff format --check . # lint + format check
|
|
41
|
+
uv run py-gate . --verbose # dogfood on ourselves
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Adding Rules
|
|
45
|
+
|
|
46
|
+
1. Create a new file in `src/pycodegate/rules/` extending `BaseRules`
|
|
47
|
+
2. Implement `check(self, source: str, filename: str) -> list[Diagnostic]`
|
|
48
|
+
3. Register in `src/pycodegate/rules/__init__.py`
|
|
49
|
+
4. Add tests in `tests/rules/`
|
|
50
|
+
|
|
51
|
+
## Architecture
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
src/pycodegate/
|
|
55
|
+
cli.py — Click CLI entry point
|
|
56
|
+
api.py — Programmatic API (diagnose function)
|
|
57
|
+
scan.py — Orchestrator: parallel lint + dead code
|
|
58
|
+
score.py — Score calculation from diagnostics
|
|
59
|
+
config.py — Config loading (py-gate.toml / pyproject.toml)
|
|
60
|
+
discover.py — Project detection (framework, package manager, etc.)
|
|
61
|
+
output.py — Rich terminal output
|
|
62
|
+
types.py — All data types (Diagnostic, Score, etc.)
|
|
63
|
+
constants.py — Magic numbers and thresholds
|
|
64
|
+
rules/
|
|
65
|
+
base.py — Abstract BaseRules with AST parsing
|
|
66
|
+
security.py — eval, exec, pickle, yaml, secrets, hashes
|
|
67
|
+
performance.py — string concat, imports in functions, star imports
|
|
68
|
+
architecture.py — giant modules, nesting, god functions, too many args
|
|
69
|
+
correctness.py — mutable defaults, bare except, assert, return in init
|
|
70
|
+
django.py — raw SQL, DEBUG, SECRET_KEY, N+1
|
|
71
|
+
fastapi.py — sync endpoints, missing response_model
|
|
72
|
+
flask.py — secret key, debug mode, SQL f-strings
|
|
73
|
+
dead_code.py — Vulture integration
|
|
74
|
+
utils/
|
|
75
|
+
file_discovery.py — Python file discovery (git + fallback)
|
|
76
|
+
ast_helpers.py — Common AST utilities
|
|
77
|
+
diff.py — Git diff file resolution
|
|
78
|
+
```
|
pycodegate-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mohit Khare
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pycodegate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: One command. One score. Your Python quality gate.
|
|
5
|
+
Project-URL: Homepage, https://github.com/themohitkhare/pycodegate
|
|
6
|
+
Project-URL: Repository, https://github.com/themohitkhare/pycodegate
|
|
7
|
+
Project-URL: Issues, https://github.com/themohitkhare/pycodegate/issues
|
|
8
|
+
Author: Mohit Khare
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai-agents,code-quality,developer-tools,linting,python,quality-gate,static-analysis
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
22
|
+
Classifier: Topic :: Software Development :: Testing
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: click>=8.1
|
|
26
|
+
Requires-Dist: rich>=13.0
|
|
27
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
28
|
+
Requires-Dist: vulture>=2.11
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
<h1 align="center">Py Gate</h1>
|
|
36
|
+
<p align="center">
|
|
37
|
+
<strong>One command. One score. Your Python quality gate.</strong>
|
|
38
|
+
</p>
|
|
39
|
+
<p align="center">
|
|
40
|
+
<a href="https://github.com/themohitkhare/pycodegate/actions/workflows/ci.yml"><img src="https://github.com/themohitkhare/pycodegate/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
41
|
+
<a href="https://pypi.org/project/py-gate/"><img src="https://img.shields.io/pypi/v/py-gate" alt="PyPI"></a>
|
|
42
|
+
<a href="https://pypi.org/project/py-gate/"><img src="https://img.shields.io/pypi/pyversions/py-gate" alt="Python"></a>
|
|
43
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## How it works
|
|
49
|
+
|
|
50
|
+
Py Gate starts by detecting your project's context: framework (Django, FastAPI, Flask), Python version, package manager (uv, poetry, pip), and test framework. That context drives which rules are active — Django projects get SQL injection checks, FastAPI projects get async-correctness checks, and so on.
|
|
51
|
+
|
|
52
|
+
It then runs two analysis passes **in parallel**: a lint pass that evaluates 40+ rules across 8 categories (Security, Correctness, Complexity, Architecture, Performance, Structure, Imports, Dead Code), and a dead-code pass powered by [Vulture](https://github.com/jendrikseipp/vulture) that finds unused functions, classes, imports, and variables.
|
|
53
|
+
|
|
54
|
+
Findings are filtered through your configuration and scored using a **weighted category-budget system**. Each category has a maximum deduction budget proportional to its weight. Within a category the top 3 findings apply at full cost; additional findings apply diminishing returns (10% each), so fixing the worst issues always moves the needle. The final result is a **0–100 health score** with a label: Excellent (90+), Great (75–89), Needs work (50–74), or Critical (<50).
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
Run instantly with `uvx` — no install needed:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
uvx py-gate .
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Install globally with pipx or uv:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pipx install py-gate
|
|
68
|
+
# or
|
|
69
|
+
uv tool install py-gate
|
|
70
|
+
# or
|
|
71
|
+
pip install py-gate
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Basic scan — score + summary
|
|
78
|
+
py-gate .
|
|
79
|
+
|
|
80
|
+
# Show file paths and line numbers for every finding
|
|
81
|
+
py-gate . --verbose
|
|
82
|
+
|
|
83
|
+
# Machine-readable output for AI agents and CI
|
|
84
|
+
py-gate . --json
|
|
85
|
+
|
|
86
|
+
# Auto-fix ruff-fixable issues, then scan
|
|
87
|
+
py-gate . --fix
|
|
88
|
+
|
|
89
|
+
# Output only the numeric score (useful in scripts)
|
|
90
|
+
py-gate . --score
|
|
91
|
+
|
|
92
|
+
# Scan only files changed vs a base branch
|
|
93
|
+
py-gate . --diff main
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## JSON Output
|
|
97
|
+
|
|
98
|
+
Pass `--json` to get structured output that AI agents and CI pipelines can parse:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
py-gate . --json
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"version": "0.1.0",
|
|
107
|
+
"path": ".",
|
|
108
|
+
"score": 87,
|
|
109
|
+
"label": "Great",
|
|
110
|
+
"errors": 1,
|
|
111
|
+
"warnings": 4,
|
|
112
|
+
"elapsed_ms": 212,
|
|
113
|
+
"project": {
|
|
114
|
+
"framework": "fastapi",
|
|
115
|
+
"python_version": "3.12",
|
|
116
|
+
"package_manager": "uv",
|
|
117
|
+
"test_framework": "pytest"
|
|
118
|
+
},
|
|
119
|
+
"diagnostics": [
|
|
120
|
+
{
|
|
121
|
+
"rule": "no-mutable-default",
|
|
122
|
+
"severity": "error",
|
|
123
|
+
"category": "Correctness",
|
|
124
|
+
"message": "Mutable default argument `[]` is shared across all calls",
|
|
125
|
+
"file_path": "src/api/routes.py",
|
|
126
|
+
"line": 34
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"rule": "high-complexity",
|
|
130
|
+
"severity": "warning",
|
|
131
|
+
"category": "Complexity",
|
|
132
|
+
"message": "Function 'process_order' has cyclomatic complexity 17 (max 15)",
|
|
133
|
+
"file_path": "src/api/orders.py",
|
|
134
|
+
"line": 88
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Agent Integration
|
|
141
|
+
|
|
142
|
+
Py Gate is designed to be used by AI coding agents. Add it to your agent's context so it runs after every Python change.
|
|
143
|
+
|
|
144
|
+
### Claude Code
|
|
145
|
+
|
|
146
|
+
Add the skill to your project:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
mkdir -p .claude/skills
|
|
150
|
+
curl -fsSL https://raw.githubusercontent.com/themohitkhare/pycodegate/main/skills/py-gate/SKILL.md \
|
|
151
|
+
-o .claude/skills/py-gate.md
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Or copy `AGENTS.md` to your project root — Claude Code picks it up automatically.
|
|
155
|
+
|
|
156
|
+
### Cursor
|
|
157
|
+
|
|
158
|
+
Add to `.cursor/rules/py-gate.mdc`:
|
|
159
|
+
|
|
160
|
+
```markdown
|
|
161
|
+
After modifying Python files, run `uvx py-gate . --json` and fix all findings
|
|
162
|
+
with severity "error" before marking the task complete. Target score: 80+.
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Windsurf
|
|
166
|
+
|
|
167
|
+
Add to `.windsurfrules`:
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
After modifying Python files, run: uvx py-gate . --json
|
|
171
|
+
Fix all "error" severity findings. Re-run to verify the score improved.
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Codex
|
|
175
|
+
|
|
176
|
+
Add to your system prompt:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
After modifying Python files, run `uvx py-gate . --json` to check code quality.
|
|
180
|
+
Fix errors first. Target score: 80+.
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Aider
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
aider --read AGENTS.md
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## GitHub Actions
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
name: Quality Gate
|
|
193
|
+
|
|
194
|
+
on: [push, pull_request]
|
|
195
|
+
|
|
196
|
+
jobs:
|
|
197
|
+
py-gate:
|
|
198
|
+
runs-on: ubuntu-latest
|
|
199
|
+
steps:
|
|
200
|
+
- uses: actions/checkout@v4
|
|
201
|
+
with:
|
|
202
|
+
fetch-depth: 0 # required for --diff
|
|
203
|
+
|
|
204
|
+
- uses: actions/setup-python@v5
|
|
205
|
+
with:
|
|
206
|
+
python-version: "3.12"
|
|
207
|
+
|
|
208
|
+
- name: Run Py Gate
|
|
209
|
+
run: |
|
|
210
|
+
pip install py-gate
|
|
211
|
+
py-gate . --verbose --diff main --fail-on error
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## CLI Reference
|
|
215
|
+
|
|
216
|
+
| Flag | Default | Description |
|
|
217
|
+
|------|---------|-------------|
|
|
218
|
+
| `[DIRECTORY]` | `.` | Path to the Python project to scan |
|
|
219
|
+
| `--lint / --no-lint` | on | Enable or disable lint checks |
|
|
220
|
+
| `--dead-code / --no-dead-code` | on | Enable or disable dead code detection |
|
|
221
|
+
| `--verbose` | off | Show file path and line number per finding |
|
|
222
|
+
| `--score` | off | Print only the numeric score and exit |
|
|
223
|
+
| `--json` | off | Emit structured JSON (for agents and CI) |
|
|
224
|
+
| `--fix` | off | Run `ruff --fix` before scanning |
|
|
225
|
+
| `--diff TEXT` | — | Scan only files changed vs this base branch |
|
|
226
|
+
| `--fail-on [error\|warning\|none]` | `none` | Exit code 1 when findings at this level exist |
|
|
227
|
+
| `-v, --version` | — | Show version and exit |
|
|
228
|
+
| `-h, --help` | — | Show help and exit |
|
|
229
|
+
|
|
230
|
+
## What It Checks
|
|
231
|
+
|
|
232
|
+
| Category | Weight | Max Deduction | What it catches |
|
|
233
|
+
|----------|--------|---------------|-----------------|
|
|
234
|
+
| Security | 5 | ~24 pts | `eval`, `exec`, `pickle.load`, unsafe YAML, hardcoded secrets, weak hashes |
|
|
235
|
+
| Correctness | 4 | ~19 pts | Mutable defaults, bare/broad except, assert in production, bad `__init__` return |
|
|
236
|
+
| Complexity | 3 | ~14 pts | Cyclomatic complexity > 15 (warning) or > 25 (error) |
|
|
237
|
+
| Architecture | 3 | ~14 pts | Giant modules (>500 lines), deep nesting (>5), god functions (>50 lines), too many args (>7) |
|
|
238
|
+
| Performance | 2 | ~10 pts | String concat in loops, imports inside functions, star imports |
|
|
239
|
+
| Structure | 2 | ~10 pts | Missing `__init__.py`, missing tests directory, no type hints |
|
|
240
|
+
| Imports | 1 | ~5 pts | Circular imports, wildcard imports, import order issues |
|
|
241
|
+
| Dead Code | 1 | ~5 pts | Unused functions, classes, variables, and imports via Vulture |
|
|
242
|
+
|
|
243
|
+
Framework-specific rules (Django, FastAPI, Flask) are mapped into the Security or Correctness budget.
|
|
244
|
+
|
|
245
|
+
## Scoring
|
|
246
|
+
|
|
247
|
+
Py Gate uses a **weighted category-budget system**:
|
|
248
|
+
|
|
249
|
+
1. Each category has a weight (see table above). Weights are normalized to sum to 100 points of total deduction budget.
|
|
250
|
+
2. Within a category, findings are sorted by cost (errors cost more than warnings). The top 3 findings apply at full cost; every additional finding applies **diminishing returns** (10% of its cost).
|
|
251
|
+
3. A category's deduction is capped at its budget, so a single broken category can never zero out an otherwise healthy project.
|
|
252
|
+
4. Final score = `100 - sum(capped category deductions)`, floored at 0.
|
|
253
|
+
|
|
254
|
+
| Score | Label | Meaning |
|
|
255
|
+
|-------|-------|---------|
|
|
256
|
+
| 90–100 | Excellent | Production-ready |
|
|
257
|
+
| 75–89 | Great | Minor issues to address |
|
|
258
|
+
| 50–74 | Needs work | Significant issues present |
|
|
259
|
+
| 0–49 | Critical | Blocking issues, do not ship |
|
|
260
|
+
|
|
261
|
+
## Configuration
|
|
262
|
+
|
|
263
|
+
Create `py-gate.toml` in your project root:
|
|
264
|
+
|
|
265
|
+
```toml
|
|
266
|
+
[options]
|
|
267
|
+
lint = true
|
|
268
|
+
dead_code = true
|
|
269
|
+
verbose = false
|
|
270
|
+
fail_on = "none"
|
|
271
|
+
|
|
272
|
+
[ignore]
|
|
273
|
+
rules = ["dead-code", "no-import-in-function"]
|
|
274
|
+
files = ["tests/fixtures/**", "migrations/**", "scripts/**"]
|
|
275
|
+
|
|
276
|
+
[per-file-ignores]
|
|
277
|
+
"src/legacy/*.py" = ["high-complexity", "no-god-function"]
|
|
278
|
+
|
|
279
|
+
[scoring]
|
|
280
|
+
max-deduction.Security = 20
|
|
281
|
+
max-deduction.Dead Code = 0 # disable dead-code penalty entirely
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Or use `pyproject.toml`:
|
|
285
|
+
|
|
286
|
+
```toml
|
|
287
|
+
[tool.py-gate]
|
|
288
|
+
lint = true
|
|
289
|
+
dead_code = true
|
|
290
|
+
fail_on = "error"
|
|
291
|
+
|
|
292
|
+
[tool.py-gate.ignore]
|
|
293
|
+
rules = ["no-import-in-function"]
|
|
294
|
+
files = ["tests/fixtures/**"]
|
|
295
|
+
|
|
296
|
+
[tool.py-gate.per-file-ignores]
|
|
297
|
+
"src/legacy/*.py" = ["high-complexity"]
|
|
298
|
+
|
|
299
|
+
[tool.py-gate.scoring]
|
|
300
|
+
"max-deduction" = { Security = 20, "Dead Code" = 0 }
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
If both files exist, `py-gate.toml` takes precedence. CLI flags always override config values.
|
|
304
|
+
|
|
305
|
+
## Profiles
|
|
306
|
+
|
|
307
|
+
Py Gate auto-detects a project profile and adjusts rule weights accordingly. You can also set a profile explicitly in config (`profile = "library"`).
|
|
308
|
+
|
|
309
|
+
| Profile | Auto-detected when | Adjustments |
|
|
310
|
+
|---------|--------------------|-------------|
|
|
311
|
+
| `cli` | `[project.scripts]` in pyproject.toml | Architecture rules weighted up; dead-code weighted down |
|
|
312
|
+
| `web` | Django / FastAPI / Flask detected | Security and correctness weighted up; framework rules active |
|
|
313
|
+
| `library` | No scripts, no framework, has `py.typed` | Public API checks active; dead-code weighted up |
|
|
314
|
+
| `script` | Single-file project or `scripts/` directory | Architecture rules relaxed; complexity thresholds raised |
|
|
315
|
+
|
|
316
|
+
## Pre-commit Hook
|
|
317
|
+
|
|
318
|
+
Use `--pre-commit` to run Py Gate as a pre-commit hook. It automatically scans only the staged files:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
py-gate . --pre-commit --fail-on error
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Add to `.pre-commit-config.yaml`:
|
|
325
|
+
|
|
326
|
+
```yaml
|
|
327
|
+
repos:
|
|
328
|
+
- repo: local
|
|
329
|
+
hooks:
|
|
330
|
+
- id: py-gate
|
|
331
|
+
name: Py Gate quality check
|
|
332
|
+
entry: py-gate . --pre-commit --fail-on error
|
|
333
|
+
language: system
|
|
334
|
+
types: [python]
|
|
335
|
+
pass_filenames: false
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Contributing
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
git clone https://github.com/themohitkhare/pycodegate
|
|
342
|
+
cd pycodegate
|
|
343
|
+
uv sync --all-extras
|
|
344
|
+
uv run pytest -q
|
|
345
|
+
uv run py-gate . --verbose # dogfood it
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
To add a new rule:
|
|
349
|
+
|
|
350
|
+
1. Create a file in `src/pycodegate/rules/` extending `BaseRules`
|
|
351
|
+
2. Implement `check(self, source: str, filename: str) -> list[Diagnostic]`
|
|
352
|
+
3. Register it in `src/pycodegate/rules/__init__.py`
|
|
353
|
+
4. Add tests in `tests/rules/`
|
|
354
|
+
|
|
355
|
+
## License
|
|
356
|
+
|
|
357
|
+
MIT
|