lintle 0.1.1__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 (33) hide show
  1. lintle-0.1.1/.github/workflows/publish.yml +50 -0
  2. lintle-0.1.1/.gitignore +29 -0
  3. lintle-0.1.1/.python-version +1 -0
  4. lintle-0.1.1/CHANGELOG.md +63 -0
  5. lintle-0.1.1/CLAUDE.md +129 -0
  6. lintle-0.1.1/CONTRIBUTING.md +144 -0
  7. lintle-0.1.1/LICENSE +21 -0
  8. lintle-0.1.1/PKG-INFO +251 -0
  9. lintle-0.1.1/README.md +226 -0
  10. lintle-0.1.1/docs/superpowers/plans/2026-05-21-tle-corpus-cleaner.md +2077 -0
  11. lintle-0.1.1/docs/superpowers/plans/2026-05-22-conventions-alignment.md +968 -0
  12. lintle-0.1.1/docs/superpowers/runs/2026-05-22-corpus-run-report.md +65 -0
  13. lintle-0.1.1/docs/superpowers/runs/2026-05-22-corpus-run-summary.json +391 -0
  14. lintle-0.1.1/docs/superpowers/specs/2026-05-21-tle-corpus-cleaner-design.md +549 -0
  15. lintle-0.1.1/docs/superpowers/specs/2026-05-22-conventions-alignment-design.md +140 -0
  16. lintle-0.1.1/pyproject.toml +69 -0
  17. lintle-0.1.1/src/lintle/__init__.py +17 -0
  18. lintle-0.1.1/src/lintle/__main__.py +8 -0
  19. lintle-0.1.1/src/lintle/cli.py +441 -0
  20. lintle-0.1.1/src/lintle/pipeline.py +205 -0
  21. lintle-0.1.1/src/lintle/repair.py +140 -0
  22. lintle-0.1.1/src/lintle/report.py +197 -0
  23. lintle-0.1.1/src/lintle/tle.py +217 -0
  24. lintle-0.1.1/tests/__init__.py +0 -0
  25. lintle-0.1.1/tests/conftest.py +26 -0
  26. lintle-0.1.1/tests/test_cli.py +384 -0
  27. lintle-0.1.1/tests/test_integration.py +86 -0
  28. lintle-0.1.1/tests/test_oracle.py +16 -0
  29. lintle-0.1.1/tests/test_pipeline.py +178 -0
  30. lintle-0.1.1/tests/test_repair.py +111 -0
  31. lintle-0.1.1/tests/test_report.py +153 -0
  32. lintle-0.1.1/tests/test_tle.py +101 -0
  33. lintle-0.1.1/uv.lock +314 -0
@@ -0,0 +1,50 @@
1
+ name: Publish
2
+
3
+ # Manually triggered. Pick the target from the input dropdown (defaults to
4
+ # the TestPyPI sandbox), and click Run workflow. Trusted Publishing (OIDC)
5
+ # handles authentication for both PyPI and TestPyPI — no API tokens stored.
6
+
7
+ on:
8
+ workflow_dispatch:
9
+ inputs:
10
+ target:
11
+ description: "Where to publish"
12
+ type: choice
13
+ options:
14
+ - testpypi
15
+ - pypi
16
+ default: testpypi
17
+
18
+ jobs:
19
+ publish:
20
+ runs-on: ubuntu-latest
21
+ environment:
22
+ name: pypi
23
+ url: ${{ inputs.target == 'pypi' && 'https://pypi.org/project/lintle/' || 'https://test.pypi.org/project/lintle/' }}
24
+ permissions:
25
+ id-token: write # required for Trusted Publishing (OIDC)
26
+ steps:
27
+ - uses: actions/checkout@v6
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@v8.1.0
31
+ with:
32
+ python-version: "3.11"
33
+
34
+ - name: Verify before publishing
35
+ run: |
36
+ uv sync
37
+ uv run pytest
38
+ uv run ruff check .
39
+ uv run ruff format --check .
40
+
41
+ - name: Build sdist and wheel
42
+ run: uv build
43
+
44
+ - name: Publish to TestPyPI
45
+ if: inputs.target == 'testpypi'
46
+ run: uv publish --index testpypi --trusted-publishing always
47
+
48
+ - name: Publish to PyPI
49
+ if: inputs.target == 'pypi'
50
+ run: uv publish --trusted-publishing always
@@ -0,0 +1,29 @@
1
+ # TLE corpus data — multi-gigabyte inputs and cleaner output, not version-controlled.
2
+ # data/source/ holds the raw tle*.txt files and TLEs.zip; data/output/ is where
3
+ # the cleaner writes <name>.cleaned.txt / <name>.broken.txt.
4
+ /data/
5
+
6
+ # Legacy / alternate locations (in case files are placed at the repo root)
7
+ /tle*.txt
8
+ /*.zip
9
+ /cleaned/
10
+ /output/
11
+
12
+ # Claude Code session state
13
+ /.claude/
14
+
15
+ # macOS
16
+ .DS_Store
17
+
18
+ # Python
19
+ __pycache__/
20
+ *.py[cod]
21
+ .venv/
22
+ venv/
23
+ *.egg-info/
24
+ .pytest_cache/
25
+ .ruff_cache/
26
+ .coverage
27
+ htmlcov/
28
+ build/
29
+ dist/
@@ -0,0 +1 @@
1
+ 3.11
@@ -0,0 +1,63 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.1.1] - 2026-05-22
8
+
9
+ ### Fixed
10
+
11
+ - `lintle clean` (and `validate`) no longer crash with a `FileNotFoundError`
12
+ traceback when the default input directory `data/source` does not exist on the
13
+ host. A new input-validation step in `cli.main()` catches the situation
14
+ upfront and prints a friendly hint that points the user at `--help` and
15
+ explains how to pass paths or create the directory.
16
+ - `discover_paths` no longer silently treats a nonexistent path as a file;
17
+ missing entries are dropped (and the new `check_paths` helper rejects them at
18
+ the boundary with a clear `no such file or directory` message instead of a
19
+ crash deeper in the pipeline).
20
+ - `--jobs 0` is rejected upfront instead of silently spinning up a zero-worker
21
+ pool that hangs.
22
+
23
+ ### Added
24
+
25
+ - `--version` / `-V` on the top-level `lintle` command.
26
+ - Top-level and per-subcommand help now include an `Examples:` block and an
27
+ `Exit codes:` reference. Subcommands carry richer descriptions and metavars
28
+ (`PATH`, `DIR`, `N`) so `lintle --help` and `lintle clean --help` are
29
+ self-explanatory.
30
+ - `check_paths(paths, using_default)` — a small public helper in `cli.py` that
31
+ returns a user-facing error string for missing or unreadable inputs, or
32
+ `None` if everything is fine.
33
+
34
+ ### Changed
35
+
36
+ - The `paths` positional argument's argparse default is now `None` (resolved to
37
+ `data/source` inside `main()`) so the CLI can tell "user passed nothing" apart
38
+ from "user explicitly passed `data/source`" and tailor the error wording.
39
+ - The version string is now tracked in **one place**: `pyproject.toml`. The
40
+ `__version__` attribute in `src/lintle/__init__.py` is resolved at runtime via
41
+ `importlib.metadata.version("lintle")` (falling back to `0.0.0+local` for
42
+ uninstalled source checkouts). Future releases need only a single bump in
43
+ `pyproject.toml` — see `CONTRIBUTING.md` for the release flow.
44
+
45
+ ## [0.1.0] - 2026-05-22
46
+
47
+ ### Added
48
+
49
+ - `lintle` console script with two modes: `validate` (read-only audit) and `clean`
50
+ (writes corrected files plus quarantine sidecars).
51
+ - `tle.py` — the single TLE validator: column layout, mod-10 checksum, semantic range
52
+ checks, and paired-record validation.
53
+ - `repair.py` — speculative, validated repairs: trailing-`\` stripping, CRLF
54
+ normalisation, whitespace trimming, and deterministic checksum reconstruction.
55
+ - `pipeline.py` — constant-memory streaming with prefix-driven `1 `/`2 ` line pairing.
56
+ - `report.py` — per-file statistics, the byte-faithful `.broken.txt` quarantine sidecar,
57
+ and the Markdown run report.
58
+ - `cli.py` — argument parsing, path globbing, per-file `ProcessPoolExecutor` parallelism,
59
+ a live single-line progress display, and graceful Ctrl-C shutdown (exit code `130`).
60
+ - Test suite: 92 tests across 7 files, including an `sgp4` oracle cross-check and
61
+ golden-output / idempotence integration tests; `cli.py` is fully covered.
62
+ - Project tooling: `ruff` for linting and formatting, `pytest-cov` for coverage.
63
+ - Documentation: `README.md`, `CONTRIBUTING.md`, and this changelog.
lintle-0.1.1/CLAUDE.md ADDED
@@ -0,0 +1,129 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this
4
+ repository.
5
+
6
+ `lintle` validates and cleans a ~30 GB corpus of Two-Line Element (TLE)
7
+ satellite-tracking files exported from space-track.org.
8
+
9
+ ## Authoritative spec
10
+
11
+ The design doc at `docs/superpowers/specs/2026-05-21-tle-corpus-cleaner-design.md` is the
12
+ authoritative specification — read it before changing validation, repair, or pipeline
13
+ behaviour. It carries a revision log in its header; keep that current when the design
14
+ changes.
15
+
16
+ ## Tech Stack
17
+
18
+ Python 3.11 · uv · standard library only at runtime · `sgp4` (dev-only test oracle) ·
19
+ `pytest` · `pytest-cov` · `ruff`
20
+
21
+ The runtime is **pure standard library**. `sgp4` and `pytest` are dev-only dependencies;
22
+ `sgp4` is a test oracle and must never be imported at runtime.
23
+
24
+ ## Critical Rules — principles that must not be violated
25
+
26
+ These are the reason the design exists; an implementation that breaks them is wrong.
27
+
28
+ 1. **Validated transformation.** Never apply a fix and trust it. Apply a candidate fix,
29
+ re-run *full* validation, and commit the result only if it now passes — otherwise
30
+ quarantine.
31
+ 2. **Correctness over recovery.** Never emit a wrong-but-valid-looking record; when in
32
+ doubt, quarantine. No reconstruction of missing *data* characters. The one sanctioned
33
+ reconstruction is a missing *checksum* digit, which is deterministically recomputable —
34
+ and even that is a distinct, weaker repair tier with its own reporting.
35
+ 3. **Constant memory.** Files stream; the pairing state machine holds at most two lines.
36
+ A 3.2 GB file must never be loaded whole.
37
+ 4. **One validator definition.** "Perfect" is defined once, in `tle.py`. Never add a
38
+ second, divergent validation path.
39
+
40
+ **Report outcomes faithfully.** If tests fail, say so with the output. If a verification
41
+ step was skipped, say that rather than implying it ran. Never claim "all tests pass" when
42
+ output shows failures.
43
+
44
+ ## The corpus (`data/`, git-ignored)
45
+
46
+ - `data/source/` — 29 raw `tle*.txt` files (~30 GB) plus `TLEs.zip` (~12 GB). Inputs.
47
+ - `data/output/` — where `clean` writes `cleaned/`, `broken/`, and `report.md`. Outputs.
48
+ - The whole `data/` tree is git-ignored — ~42 GB — and must never be staged or committed.
49
+ - **Never read a corpus file whole** — the largest is 3.2 GB. Sample with `head`, `awk`,
50
+ or `sed -n`.
51
+
52
+ ## Code Style
53
+
54
+ - Python 3.11. Concise one-paragraph docstrings on every public module, function, and
55
+ class — match that established style; do not expand to Args/Returns/Raises blocks.
56
+ - `ruff` for linting and formatting, configured in `pyproject.toml` (rule sets `E`, `F`,
57
+ `I`, `UP`, `B`, `SIM`; 88-column lines).
58
+ - `src/` layout — all package code lives under `src/lintle/`.
59
+ - Run `uv run ruff check .` and `uv run ruff format --check .` before committing.
60
+
61
+ ## Project Layout
62
+
63
+ ```
64
+ src/lintle/
65
+ ├── __main__.py # python -m lintle entry point
66
+ ├── __init__.py # __version__, stem() filename helper
67
+ ├── cli.py # argparse, globbing, parallel workers, live progress, Ctrl-C handling
68
+ ├── pipeline.py # streams a file in binary, pairs 1/2 lines into records, routes them
69
+ ├── repair.py # speculative fixes, each confirmed by tle.py before commit
70
+ ├── report.py # FileStats, the .broken.txt sidecar writer, the run report
71
+ └── tle.py # the validator — column layout, checksum, semantic ranges, pairing
72
+ ```
73
+
74
+ Module dependencies point one way only: `cli.py → pipeline.py → repair.py → tle.py`.
75
+
76
+ → See [`README.md`](README.md) for the architecture, usage, and data flow.
77
+ → See [`CONTRIBUTING.md`](CONTRIBUTING.md) for setup, testing, and the git workflow.
78
+
79
+ ## Commands
80
+
81
+ ```bash
82
+ uv sync # Install, including dev deps (sgp4, pytest, ruff)
83
+ uv run pytest # Full test suite
84
+ uv run pytest tests/test_tle.py::TestComputeChecksum # A single test class
85
+ uv run pytest --cov=lintle --cov-report=term-missing --cov-branch # Tests + coverage
86
+ uv run ruff check . # Lint
87
+ uv run ruff format --check . # Format check
88
+ uv run lintle validate # Audit data/source/ (read-only)
89
+ uv run lintle clean # Clean data/source/ -> data/output/
90
+ ```
91
+
92
+ ## Working Style
93
+
94
+ - **Use agents** for codebase exploration and multi-step research tasks.
95
+ - **Always verify** after a change: run `uv run pytest`, `uv run ruff check .`, and
96
+ `uv run ruff format --check .`, and report the actual output.
97
+ - Build order, if rebuilding from the spec (§12): `pyproject.toml` → `tle.py` (test-first,
98
+ it is the correctness oracle) → `repair.py` → `pipeline.py` → `report.py` / `cli.py`.
99
+
100
+ ## Verification
101
+
102
+ After completing edits, run these before reporting success:
103
+
104
+ ```bash
105
+ uv run pytest # Must pass
106
+ uv run ruff check . # Must pass
107
+ uv run ruff format --check . # Must pass
108
+ ```
109
+
110
+ If any fail, report the actual output — do not suppress or simplify failures.
111
+
112
+ ## File Guidelines
113
+
114
+ - Never read a corpus file whole — sample with `head`, `awk`, or `sed -n`.
115
+ - When renaming a function or variable, search for direct calls, string literals
116
+ containing the name, re-exports, and test references.
117
+ - Prefer files with one clear responsibility; keep functions focused and readable.
118
+
119
+ ## Conventions
120
+
121
+ - Design docs live in `docs/superpowers/specs/`, named `YYYY-MM-DD-topic.md`. The design
122
+ doc carries a revision log in its header — keep it current when the design changes.
123
+ - Tests are grouped into `Test*` classes, one per unit or behaviour under test.
124
+ - Git: never commit to `main` directly; branch (`feature/`, `bugfix/`, `chore/`); use
125
+ conventional commits (`feat:`, `fix:`, `docs:`, `test:`, `style:`, `chore:`).
126
+ - Versioning: `pyproject.toml`'s `[project] version` is the single source of truth;
127
+ `src/lintle/__init__.py` resolves `__version__` from it at runtime via
128
+ `importlib.metadata`. Bump it once, add a `CHANGELOG.md` entry — see CONTRIBUTING.md
129
+ for the release flow.
@@ -0,0 +1,144 @@
1
+ # Contributing to lintle
2
+
3
+ ## Prerequisites
4
+
5
+ - **Python 3.11+**
6
+ - **[uv](https://docs.astral.sh/uv/)** — Python package and project manager
7
+
8
+ ## Setup
9
+
10
+ ```bash
11
+ git clone <repo-url>
12
+ cd TLEs
13
+ uv sync
14
+ ```
15
+
16
+ `uv sync` installs Python 3.11 if needed, creates a `.venv/`, and installs the project
17
+ plus all dev dependencies (`pytest`, `pytest-cov`, `sgp4`, `ruff`) from `uv.lock`.
18
+
19
+ ### Managing dependencies
20
+
21
+ Dependencies are declared in `pyproject.toml` and pinned in `uv.lock` (committed to git).
22
+
23
+ ```bash
24
+ uv add --group dev <pkg> # Add a dev-only dependency
25
+ uv sync # Reinstall from the lock file (after a pull)
26
+ ```
27
+
28
+ The **runtime has no third-party dependencies** — `lintle` is pure standard library.
29
+ `sgp4` is a dev-only test oracle and must never be imported at runtime.
30
+
31
+ ## Running
32
+
33
+ ```bash
34
+ uv run lintle validate # Read-only audit of data/source/
35
+ uv run lintle clean # Write cleaned output to data/output/
36
+ ```
37
+
38
+ `uv run` executes a command inside the project virtual environment — no manual
39
+ activation needed.
40
+
41
+ ## Testing
42
+
43
+ ```bash
44
+ uv run pytest # Run all tests
45
+ uv run pytest -x # Stop on first failure
46
+ uv run pytest -k "checksum" # Run tests matching an expression
47
+ uv run pytest tests/test_tle.py # Run one file
48
+ uv run pytest tests/test_tle.py::TestComputeChecksum # Run one class
49
+ ```
50
+
51
+ ### Coverage
52
+
53
+ ```bash
54
+ uv run pytest --cov=lintle --cov-report=term-missing --cov-branch
55
+ ```
56
+
57
+ This reports line and branch coverage, listing uncovered lines in the `Missing` column.
58
+
59
+ ### Test layout
60
+
61
+ Tests are grouped into `Test*` classes, one per unit or behaviour under test.
62
+
63
+ | File | What it covers |
64
+ |------|----------------|
65
+ | `test_tle.py` | The validator: checksum, column layout, semantic ranges, record pairing |
66
+ | `test_repair.py` | Speculative line/record repair and the rejection categories |
67
+ | `test_pipeline.py` | Streaming I/O, line pairing, per-file processing, progress, temp-file safety |
68
+ | `test_report.py` | `FileStats`, the `.broken.txt` sidecar, summaries, the run report |
69
+ | `test_cli.py` | Argument parsing, path discovery, exit codes, elapsed-time formatting |
70
+ | `test_integration.py` | End-to-end: golden output, idempotence, re-validation |
71
+ | `test_oracle.py` | Cross-checks a known-good TLE against the trusted `sgp4` parser |
72
+
73
+ `conftest.py` holds the shared `line1` / `line2` fixtures — a canonical, known-good TLE.
74
+
75
+ ## Linting & Formatting
76
+
77
+ [Ruff](https://docs.astral.sh/ruff/) handles both linting and formatting. Its
78
+ configuration lives in `pyproject.toml` under `[tool.ruff]` (rule sets `E`, `F`, `I`,
79
+ `UP`, `B`, `SIM`; 88-column lines).
80
+
81
+ ```bash
82
+ uv run ruff check . # Lint
83
+ uv run ruff check . --fix # Lint with auto-fix
84
+ uv run ruff format . # Format
85
+ uv run ruff format --check . # Check formatting (no writes)
86
+ ```
87
+
88
+ Run both before committing:
89
+
90
+ ```bash
91
+ uv run ruff check . && uv run ruff format --check .
92
+ ```
93
+
94
+ ## Verification
95
+
96
+ Before reporting any change as done, run — and report the actual output of:
97
+
98
+ ```bash
99
+ uv run pytest
100
+ uv run ruff check .
101
+ uv run ruff format --check .
102
+ ```
103
+
104
+ Never claim success without the output. If a check fails, report the failure.
105
+
106
+ ## Git Workflow
107
+
108
+ - **Never commit directly to `main`.** Branch for every change.
109
+ - Branch names: `feature/<desc>`, `bugfix/<desc>`, `chore/<desc>` — lowercase, hyphens.
110
+ - Use [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`,
111
+ `docs:`, `test:`, `refactor:`, `style:`, `chore:`.
112
+ - Open a pull request to `main`; run the verification commands above before merging.
113
+
114
+ ## Versioning
115
+
116
+ Semantic versioning (`MAJOR.MINOR.PATCH`). The version lives in **one place** —
117
+ `pyproject.toml`'s `[project] version` field — and is resolved at runtime from the
118
+ installed distribution metadata by `src/lintle/__init__.py`:
119
+
120
+ ```python
121
+ from importlib.metadata import PackageNotFoundError, version as _dist_version
122
+
123
+ try:
124
+ __version__ = _dist_version("lintle")
125
+ except PackageNotFoundError: # source checkout that was never installed
126
+ __version__ = "0.0.0+local"
127
+ ```
128
+
129
+ Because the lookup needs the project to be installed (even editable), keep `uv sync`
130
+ current — every dev workflow in this repo already does.
131
+
132
+ Release flow:
133
+
134
+ 1. Bump `version` in `pyproject.toml`.
135
+ 2. Add a new `## [X.Y.Z] - YYYY-MM-DD` section at the top of `CHANGELOG.md` with
136
+ `### Added` / `### Changed` / `### Fixed` subsections (see Keep a Changelog).
137
+ 3. Run the verification commands (`uv run pytest`, `uv run ruff check .`,
138
+ `uv run ruff format --check .`) and report the actual output.
139
+ 4. Commit on a `chore/release-X.Y.Z` branch and open a PR to `main`. Tag and publish
140
+ after merge.
141
+
142
+ Nothing else needs to change — `lintle --version`, the `report.py` headers, and any
143
+ downstream `from lintle import __version__` import all pick the new value up from
144
+ `pyproject.toml` automatically.
lintle-0.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andrei Lavrenov
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.