lintex 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.
Files changed (47) hide show
  1. lintex-0.1.0/.github/workflows/ci.yml +41 -0
  2. lintex-0.1.0/.github/workflows/release.yml +73 -0
  3. lintex-0.1.0/.gitignore +13 -0
  4. lintex-0.1.0/.pre-commit-hooks.yaml +7 -0
  5. lintex-0.1.0/CHANGELOG.md +47 -0
  6. lintex-0.1.0/CONTRIBUTING.md +71 -0
  7. lintex-0.1.0/LICENSE +21 -0
  8. lintex-0.1.0/PKG-INFO +420 -0
  9. lintex-0.1.0/README.md +390 -0
  10. lintex-0.1.0/SECURITY.md +15 -0
  11. lintex-0.1.0/pyproject.toml +88 -0
  12. lintex-0.1.0/src/lintex/__init__.py +22 -0
  13. lintex-0.1.0/src/lintex/__main__.py +3 -0
  14. lintex-0.1.0/src/lintex/cli.py +475 -0
  15. lintex-0.1.0/src/lintex/config.py +291 -0
  16. lintex-0.1.0/src/lintex/engine.py +304 -0
  17. lintex-0.1.0/src/lintex/hooks/__init__.py +13 -0
  18. lintex-0.1.0/src/lintex/hooks/claude_code.py +119 -0
  19. lintex-0.1.0/src/lintex/hooks/git.py +124 -0
  20. lintex-0.1.0/src/lintex/hooks/statusline.py +119 -0
  21. lintex-0.1.0/src/lintex/knowledge/__init__.py +164 -0
  22. lintex-0.1.0/src/lintex/knowledge/__main__.py +3 -0
  23. lintex-0.1.0/src/lintex/knowledge/curated.toml +742 -0
  24. lintex-0.1.0/src/lintex/knowledge/sync.py +251 -0
  25. lintex-0.1.0/src/lintex/knowledge/typeshed.json +1248 -0
  26. lintex-0.1.0/src/lintex/ledger.py +292 -0
  27. lintex-0.1.0/src/lintex/models.py +66 -0
  28. lintex-0.1.0/src/lintex/py.typed +0 -0
  29. lintex-0.1.0/src/lintex/reporters.py +315 -0
  30. lintex-0.1.0/src/lintex/rules/__init__.py +116 -0
  31. lintex-0.1.0/src/lintex/rules/agent_artifacts.py +180 -0
  32. lintex-0.1.0/src/lintex/rules/banned_patterns.py +529 -0
  33. lintex-0.1.0/src/lintex/rules/base.py +226 -0
  34. lintex-0.1.0/src/lintex/rules/bloat.py +275 -0
  35. lintex-0.1.0/src/lintex/rules/hallucinations.py +410 -0
  36. lintex-0.1.0/tests/conftest.py +29 -0
  37. lintex-0.1.0/tests/test_changed.py +114 -0
  38. lintex-0.1.0/tests/test_cli.py +148 -0
  39. lintex-0.1.0/tests/test_config.py +75 -0
  40. lintex-0.1.0/tests/test_engine.py +97 -0
  41. lintex-0.1.0/tests/test_knowledge.py +182 -0
  42. lintex-0.1.0/tests/test_ledger.py +199 -0
  43. lintex-0.1.0/tests/test_reporters.py +107 -0
  44. lintex-0.1.0/tests/test_rules_agent_artifacts.py +59 -0
  45. lintex-0.1.0/tests/test_rules_banned.py +98 -0
  46. lintex-0.1.0/tests/test_rules_bloat.py +72 -0
  47. lintex-0.1.0/tests/test_rules_hallucinations.py +115 -0
@@ -0,0 +1,41 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ # Pinned: `ubuntu-latest` moved to 26.04, which has no Python 3.9 build for
15
+ # actions/setup-python, and we support 3.9.
16
+ os: [ubuntu-24.04]
17
+ python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
18
+ include:
19
+ - os: windows-latest
20
+ python: "3.13"
21
+ - os: macos-latest
22
+ python: "3.13"
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version: ${{ matrix.python }}
28
+ - run: python -m pip install -e . pytest pyyaml
29
+ - run: python -m pytest
30
+
31
+ lint:
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: actions/setup-python@v5
36
+ with:
37
+ python-version: "3.13"
38
+ - run: python -m pip install -e . ruff
39
+ - run: ruff check src tests
40
+ - run: ruff format --check src tests
41
+ - run: lintex check . --format github
@@ -0,0 +1,73 @@
1
+ name: Release
2
+
3
+ # Publishes to PyPI when a version tag (e.g. v0.1.0) is pushed, or to TestPyPI
4
+ # (or PyPI) on demand from the Actions tab. Uses trusted publishing, so no
5
+ # tokens are stored: configure a trusted publisher for this repository and
6
+ # workflow at https://pypi.org/manage/account/publishing/ (environment `pypi`)
7
+ # and, for rehearsals, at https://test.pypi.org/manage/account/publishing/
8
+ # (environment `testpypi`).
9
+ on:
10
+ push:
11
+ tags: ["v*"]
12
+ workflow_dispatch:
13
+ inputs:
14
+ target:
15
+ description: "Where to publish"
16
+ type: choice
17
+ options: [testpypi, pypi]
18
+ default: testpypi
19
+
20
+ jobs:
21
+ build:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.13"
28
+ - run: python -m pip install build twine
29
+ - name: Check the tag matches the package version
30
+ if: startsWith(github.ref, 'refs/tags/v')
31
+ run: |
32
+ version=$(python -c "import re,pathlib;print(re.search(r'__version__ = \"([^\"]+)\"', pathlib.Path('src/lintex/__init__.py').read_text()).group(1))")
33
+ tag="${GITHUB_REF_NAME#v}"
34
+ if [ "$version" != "$tag" ]; then
35
+ echo "tag v$tag does not match __version__ $version" >&2
36
+ exit 1
37
+ fi
38
+ - run: python -m build
39
+ - run: python -m twine check --strict dist/*
40
+ - name: Smoke-test the wheel in a clean environment
41
+ run: |
42
+ python -m venv /tmp/smoke && /tmp/smoke/bin/pip install -q dist/*.whl
43
+ /tmp/smoke/bin/lintex --version
44
+ echo 'from collections import Mapping' > /tmp/smoke/x.py
45
+ # lintex exits 1 when it finds something, which is what we expect here.
46
+ # Capture the status so `bash -e` (the Actions default) doesn't abort on it.
47
+ status=0
48
+ /tmp/smoke/bin/lintex check /tmp/smoke/x.py --format concise --no-color || status=$?
49
+ test "$status" -eq 1
50
+ - uses: actions/upload-artifact@v4
51
+ with:
52
+ name: dist
53
+ path: dist/
54
+
55
+ publish:
56
+ needs: build
57
+ runs-on: ubuntu-latest
58
+ environment: ${{ github.event_name == 'workflow_dispatch' && inputs.target || 'pypi' }}
59
+ permissions:
60
+ id-token: write
61
+ steps:
62
+ - uses: actions/download-artifact@v4
63
+ with:
64
+ name: dist
65
+ path: dist/
66
+ - name: Publish to TestPyPI
67
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
68
+ uses: pypa/gh-action-pypi-publish@release/v1
69
+ with:
70
+ repository-url: https://test.pypi.org/legacy/
71
+ - name: Publish to PyPI
72
+ if: github.event_name != 'workflow_dispatch' || inputs.target == 'pypi'
73
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ .mypy_cache/
12
+ .coverage
13
+ htmlcov/
@@ -0,0 +1,7 @@
1
+ - id: lintex
2
+ name: lintex
3
+ description: Lint Python code written by LLM coding agents.
4
+ entry: lintex check
5
+ language: python
6
+ types: [python]
7
+ require_serial: false
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to lintex are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/). While the version is 0.x, rule defaults and
6
+ severities may change between minor versions as they are tuned on real codebases.
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-10-23
11
+
12
+ First release.
13
+
14
+ ### Rules
15
+
16
+ - **LX001** syntax-error: the file does not parse (often a truncated edit).
17
+ - **LX101** hallucinated-api: removed, deprecated or Python-2-only APIs, from a curated pack
18
+ and a pack generated from typeshed. Stdlib removals are judged against the project's minimum
19
+ Python (`requires-python` or `target-version`).
20
+ - **LX102** nonexistent-stdlib-name: names that don't exist in a stdlib module, with
21
+ "did you mean" suggestions (Python 3.10+).
22
+ - **LX103** unresolvable-import (opt-in): imports that aren't installed, stdlib or local.
23
+ - **LX201** sql-string-interpolation: SQL built with f-strings, `.format()`, `%` or `+`.
24
+ - **LX202** raw-sql (opt-in): any raw SQL, for ORM-only projects.
25
+ - **LX203** dangerous-call: `eval`/`exec`, unsafe deserialization, `yaml.load` without a safe
26
+ loader, `os.system`, `shell=True`, `verify=False`.
27
+ - **LX204** insecure-file-operation: `tempfile.mktemp`, world-writable modes, tar
28
+ `extractall()` without `filter=`, hard-coded `/tmp` paths.
29
+ - **LX205** banned-api: project-specific banned modules and functions with custom messages.
30
+ - **LX301–LX305** agent bloat: function length, cyclomatic complexity, parameter count,
31
+ nesting depth, module length.
32
+ - **LX401** placeholder-code: comments standing in for elided code, stub markers.
33
+ - **LX402** swallowed-exception, **LX403** bare-except.
34
+
35
+ ### Tooling
36
+
37
+ - `lintex check` with `--format pretty|full|concise|github|json`, `--staged`, `--changed`,
38
+ `--select`/`--ignore`/`--enable`, `--fail-on`, inline `# lintex: ignore[CODE]` and
39
+ `# lintex: skip-file`.
40
+ - Configuration in `pyproject.toml` `[tool.lintex]`, `.lintex.toml` or `.lintex.yaml`.
41
+ - Claude Code `PostToolUse` hook that feeds findings (with `why` and `fix`) back to the agent.
42
+ - Session ledger with `lintex report` and a Claude Code status line (`lintex statusline`).
43
+ - Git pre-commit hook (`lintex install-hook git`) and a `.pre-commit-hooks.yaml`.
44
+ - `python -m lintex.knowledge.sync` to regenerate the typeshed knowledge pack.
45
+
46
+ [Unreleased]: https://github.com/700799/lintex/compare/v0.1.0...HEAD
47
+ [0.1.0]: https://github.com/700799/lintex/releases/tag/v0.1.0
@@ -0,0 +1,71 @@
1
+ # Contributing to lintex
2
+
3
+ Thanks for helping. The most valuable contributions, in order, are: a false positive with a
4
+ minimal reproduction, a new API knowledge entry, and a new rule.
5
+
6
+ ## Set up
7
+
8
+ ```bash
9
+ git clone https://github.com/700799/lintex && cd lintex
10
+ python -m venv .venv && . .venv/bin/activate
11
+ pip install -e . pytest pyyaml ruff mypy
12
+ pytest # the suite runs in well under a second
13
+ ruff check src tests && ruff format --check src tests
14
+ lintex check . # lintex lints itself and must stay clean
15
+ ```
16
+
17
+ CI runs the same three commands on Python 3.9–3.13, Windows and macOS.
18
+
19
+ ## Report a false positive
20
+
21
+ Open an issue with the smallest snippet that triggers it, the lintex version, and your
22
+ Python version. Precision matters more than recall here: a rule that cries wolf gets turned
23
+ off, so a confirmed false positive is a bug.
24
+
25
+ ## Add an API knowledge entry
26
+
27
+ Removed, deprecated and Python-2-only names for LX101 live in
28
+ `src/lintex/knowledge/curated.toml`. An entry is:
29
+
30
+ ```toml
31
+ [[api]]
32
+ name = "requests.packages.urllib3"
33
+ status = "removed" # removed | deprecated | py2
34
+ package = "requests" # omit for the standard library
35
+ version = "2.16"
36
+ fix = "Use `import urllib3` directly."
37
+ ```
38
+
39
+ Write the `fix` as something an agent can paste: the replacement, not a description of it.
40
+ Add a line to `tests/test_rules_hallucinations.py` showing it fires. Stdlib module removals and
41
+ `@deprecated` names are generated into `typeshed.json`; don't edit that file, regenerate it
42
+ with `python -m lintex.knowledge.sync --from-mypy` (stdlib) or `--typeshed PATH` (with
43
+ third-party stubs). A curated entry overrides a generated one for the same name, which is the
44
+ way to give a generated entry a better fix.
45
+
46
+ ## Add a rule
47
+
48
+ 1. Subclass `lintex.rules.base.Rule` in the module for its family (`hallucinations`,
49
+ `banned_patterns`, `bloat`, `agent_artifacts`). Set `code`, `name`, `summary`,
50
+ `explanation`, `default_severity`, `node_types` and, if configurable, `options`.
51
+ 2. Implement `check_node` (called for each node whose type is in `node_types`) and/or
52
+ `check_file`. Use `ctx.resolve(node)` to turn a Name/Attribute chain into an
53
+ import-qualified name, and `is_compat_guarded` to skip `try/except ImportError` blocks.
54
+ 3. Every violation needs a `message` (what), a `why` (the failure mode) and a `fix` (what to
55
+ write instead). Assume the reader is an LLM with no other context.
56
+ 4. Register it in `ALL_RULES` in `src/lintex/rules/__init__.py` and add tests with both a
57
+ triggering case and a clean case that looks similar.
58
+ 5. Run it over a large real codebase before opening the PR (the CPython stdlib is a good
59
+ known-good corpus: `lintex check $(python -c "import sysconfig;print(sysconfig.get_paths()['stdlib'])") --select LXnnn`).
60
+ New rules default to `warning` unless the finding is almost never wrong.
61
+
62
+ ## Keep the engine fast
63
+
64
+ Rules run inside a single AST walk, dispatched by node type. Don't re-walk the tree in a rule;
65
+ keep per-file state in `ctx.state[self.code]` and finish in `check_file`. Anything that reads
66
+ files or imports modules must be cached across files.
67
+
68
+ ## Commit messages and PRs
69
+
70
+ Explain the *why* in the commit body; the diff already shows the what. Keep PRs to one change.
71
+ A PR that adds a rule should include the false-positive numbers from the corpus run.
lintex-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 lintex contributors
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.