precisionai-pace 0.0.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 (41) hide show
  1. precisionai_pace-0.0.1/.coveragerc-adapters +20 -0
  2. precisionai_pace-0.0.1/.gitattributes +12 -0
  3. precisionai_pace-0.0.1/.gitignore +135 -0
  4. precisionai_pace-0.0.1/.pre-commit-config.yaml +47 -0
  5. precisionai_pace-0.0.1/CHANGELOG.md +28 -0
  6. precisionai_pace-0.0.1/CLAUDE.md +293 -0
  7. precisionai_pace-0.0.1/CODE_OF_CONDUCT.md +47 -0
  8. precisionai_pace-0.0.1/CONTRIBUTING.md +79 -0
  9. precisionai_pace-0.0.1/LICENSE.md +201 -0
  10. precisionai_pace-0.0.1/MANIFEST.in +11 -0
  11. precisionai_pace-0.0.1/PKG-INFO +404 -0
  12. precisionai_pace-0.0.1/README.md +154 -0
  13. precisionai_pace-0.0.1/SECURITY.md +60 -0
  14. precisionai_pace-0.0.1/precisionai/__init__.py +2 -0
  15. precisionai_pace-0.0.1/precisionai/pace/__init__.py +52 -0
  16. precisionai_pace-0.0.1/precisionai/pace/_adapters.py +166 -0
  17. precisionai_pace-0.0.1/precisionai/pace/_env.py +208 -0
  18. precisionai_pace-0.0.1/precisionai/pace/_render.py +234 -0
  19. precisionai_pace-0.0.1/precisionai/pace/capture.py +78 -0
  20. precisionai_pace-0.0.1/precisionai/pace/core.py +342 -0
  21. precisionai_pace-0.0.1/precisionai/pace/forecast.py +759 -0
  22. precisionai_pace-0.0.1/precisionai/pace/lightning.py +160 -0
  23. precisionai_pace-0.0.1/precisionai/pace/protocol.py +584 -0
  24. precisionai_pace-0.0.1/precisionai/pace/scopes.py +600 -0
  25. precisionai_pace-0.0.1/precisionai/pace/transformers.py +125 -0
  26. precisionai_pace-0.0.1/precisionai/pace/version.py +31 -0
  27. precisionai_pace-0.0.1/precisionai_pace.egg-info/PKG-INFO +404 -0
  28. precisionai_pace-0.0.1/precisionai_pace.egg-info/SOURCES.txt +39 -0
  29. precisionai_pace-0.0.1/precisionai_pace.egg-info/dependency_links.txt +1 -0
  30. precisionai_pace-0.0.1/precisionai_pace.egg-info/requires.txt +25 -0
  31. precisionai_pace-0.0.1/precisionai_pace.egg-info/scm_file_list.json +97 -0
  32. precisionai_pace-0.0.1/precisionai_pace.egg-info/scm_version.json +8 -0
  33. precisionai_pace-0.0.1/precisionai_pace.egg-info/top_level.txt +1 -0
  34. precisionai_pace-0.0.1/pyproject.toml +178 -0
  35. precisionai_pace-0.0.1/requirements-dev.txt +18 -0
  36. precisionai_pace-0.0.1/requirements.txt +3 -0
  37. precisionai_pace-0.0.1/setup.cfg +4 -0
  38. precisionai_pace-0.0.1/skills/README.md +49 -0
  39. precisionai_pace-0.0.1/skills/adopt-pace/SKILL.md +255 -0
  40. precisionai_pace-0.0.1/skills/adopt-pace/patterns.md +383 -0
  41. precisionai_pace-0.0.1/skills/adopt-pace/verify.py +470 -0
@@ -0,0 +1,20 @@
1
+ # Coverage for the framework adapters only, used by the `adapters` job in
2
+ # .github/workflows/unit-test.yml. The core matrix runs without Lightning or
3
+ # Transformers installed, so pyproject.toml leaves these two modules out of its
4
+ # coverage run and this file measures them where the frameworks are present.
5
+ [run]
6
+ include =
7
+ */precisionai/pace/lightning.py
8
+ */precisionai/pace/transformers.py
9
+ branch = true
10
+ relative_files = true
11
+
12
+ [report]
13
+ fail_under = 90
14
+ show_missing = true
15
+ exclude_lines =
16
+ pragma: no cover
17
+ if __name__ == .__main__.:
18
+ raise ImportError
19
+ except ImportError
20
+ if TYPE_CHECKING:
@@ -0,0 +1,12 @@
1
+ # Normalize line endings to LF on commit, regardless of editor/OS settings.
2
+ * text=auto eol=lf
3
+
4
+ # Treat binary files as binary (no line-ending conversion).
5
+ *.png binary
6
+ *.jpg binary
7
+ *.jpeg binary
8
+ *.JPG binary
9
+ *.JPEG binary
10
+ *.svg binary
11
+ *.pdf binary
12
+ *.ipynb text eol=lf
@@ -0,0 +1,135 @@
1
+ # Virtual environments
2
+ .venv/
3
+ env/
4
+ venv/
5
+ ENV/
6
+ env.bak/
7
+ venv.bak/
8
+
9
+ # Byte-compiled / optimized / DLL files
10
+ __pycache__/
11
+ *.py[cod]
12
+ *$py.class
13
+
14
+ # C extensions
15
+ *.so
16
+
17
+ # Distribution / packaging
18
+ .Python
19
+ build/
20
+ develop-eggs/
21
+ dist/
22
+ downloads/
23
+ eggs/
24
+ .eggs/
25
+ lib/
26
+ lib64/
27
+ parts/
28
+ sdist/
29
+ var/
30
+ wheels/
31
+ share/python-wheels/
32
+ *.egg-info/
33
+ .installed.cfg
34
+ *.egg
35
+ MANIFEST
36
+
37
+ # PyInstaller
38
+ *.manifest
39
+ *.spec
40
+
41
+ # Installer logs
42
+ pip-log.txt
43
+ pip-delete-this-directory.txt
44
+
45
+ # Unit test / coverage reports
46
+ htmlcov/
47
+ .tox/
48
+ .nox/
49
+ .coverage
50
+ .coverage.*
51
+ .cache
52
+ nosetests.xml
53
+ coverage.xml
54
+ *.cover
55
+ *.py,cover
56
+ .hypothesis/
57
+ .pytest_cache/
58
+ cover/
59
+
60
+ # Sphinx documentation
61
+ docs/_build/
62
+ docs/readme.md
63
+
64
+ # Jupyter Notebook
65
+ .ipynb_checkpoints
66
+
67
+ # IPython
68
+ profile_default/
69
+ ipython_config.py
70
+
71
+ # pyenv
72
+ .python-version
73
+
74
+ # pipenv
75
+ Pipfile.lock
76
+
77
+ # pdm
78
+ .pdm.toml
79
+
80
+ # PEP 582
81
+ __pypackages__/
82
+
83
+ # mypy
84
+ .mypy_cache/
85
+ .dmypy.json
86
+ dmypy.json
87
+
88
+ # Pyre type checker
89
+ .pyre/
90
+
91
+ # pytype static type analyzer
92
+ .pytype/
93
+
94
+ # Cython debug symbols
95
+ cython_debug/
96
+
97
+ # PyCharm
98
+ .idea/
99
+
100
+ # VS Code
101
+ .vscode/
102
+
103
+ # PyTorch / Machine Learning artefacts
104
+ *.pth
105
+ *.pt
106
+ *.ckpt
107
+ *.pkl
108
+ *.h5
109
+ *.hdf5
110
+ *.onnx
111
+ *.pb
112
+ *.tflite
113
+ *.tfl
114
+ checkpoints/
115
+ models/
116
+ weights/
117
+ wandb/
118
+ mlruns/
119
+ .neptune/
120
+
121
+ # OS files
122
+ .DS_Store
123
+ .DS_Store?
124
+ ._*
125
+ .Spotlight-V100
126
+ .Trashes
127
+ ehthumbs.db
128
+ Thumbs.db
129
+ *~
130
+
131
+ # Temporary files
132
+ *.tmp
133
+ *.temp
134
+ *.swp
135
+ *.swo
@@ -0,0 +1,47 @@
1
+ repos:
2
+ # ── File hygiene ────────────────────────────────────────────────────────────
3
+ - repo: https://github.com/pre-commit/pre-commit-hooks
4
+ rev: v6.0.0
5
+ hooks:
6
+ - id: check-added-large-files
7
+ args: ["--maxkb=1800"]
8
+ - id: check-yaml
9
+ - id: check-json
10
+ - id: check-toml
11
+ - id: end-of-file-fixer
12
+ exclude: ^\.github/badges/
13
+ - id: trailing-whitespace
14
+ exclude: ^\.github/badges/
15
+ - id: check-merge-conflict
16
+ - id: detect-private-key
17
+ - id: debug-statements
18
+ - id: fix-byte-order-marker
19
+
20
+ # ── Ruff: lint + format + import sorting ───────────────────────────────────
21
+ - repo: https://github.com/astral-sh/ruff-pre-commit
22
+ rev: v0.15.17
23
+ hooks:
24
+ - id: ruff
25
+ args: ["--fix"]
26
+ - id: ruff-format
27
+
28
+ # ── Type checking (pyright / pylance engine) ────────────────────────────────
29
+ - repo: local
30
+ hooks:
31
+ - id: pyright
32
+ name: pyright
33
+ entry: python -m pyright
34
+ language: system
35
+ types: [python]
36
+ pass_filenames: false
37
+
38
+ # ── Tests + coverage (≥ 90%) ────────────────────────────────────────────────
39
+ - repo: local
40
+ hooks:
41
+ - id: pytest
42
+ name: pytest (coverage ≥ 90%)
43
+ entry: python -m pytest
44
+ language: system
45
+ args: ["tests/", "-q", "--tb=short", "--no-header"]
46
+ pass_filenames: false
47
+ always_run: true
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.0.1] - 2026-11-03
11
+
12
+ ### Added
13
+
14
+ - Package scaffold for `precisionai-pace`, with no runtime dependencies and support for Python 3.8 and later.
15
+ - Design document for the logger, the progress line format and the completion-forecast rules.
16
+ - `logger` with `debug`, `info`, `success`, `warning`, `error`, `critical` and `exception`, writing to stdout by default, falling back to plain ASCII on terminals that cannot show Unicode, and never raising into your code.
17
+ - Progress reporting with `track`, `progress`, `timed`, `phase` and `plan`, written as readable lines that also carry a `[pace:1 ...]` trailer a scheduler can read.
18
+ - A live progress bar on terminals, and rate-limited progress lines everywhere else, so a long run writes a few lines a minute however many steps it has.
19
+ - `capture_logging()` to route the standard library's `logging` (and so PyTorch's and Transformers') through Pace.
20
+ - `parse_line` and `LineSplitter` for programs that read Pace output, with shared conformance fixtures.
21
+ - Time-remaining estimates (`ScopeForecast`, `JobForecast`) shared by the terminal display and by schedulers.
22
+ - Callbacks for PyTorch Lightning (`precisionai.pace.lightning.PaceCallback`) and Hugging Face Transformers and TRL (`precisionai.pace.transformers.PaceCallback`), installed with the `[lightning]`, `[transformers]` or `[all]` extras.
23
+ - `skills/adopt-pace/`, a Claude Code skill that adds Pace to a repository and checks the result with `verify.py`.
24
+ - Runnable examples, one per style of logging and progress (plain loops, epochs, concurrent work, phases and a plan, resuming, unknown totals, nested scopes, `logging` capture, distributed ranks, and reading the output).
25
+ - User documentation: getting started, logging, progress, framework integrations, migration guides (`print`, `tqdm`, Loguru, `logging`), configuration, a guide for programs that read Pace output, and a FAQ.
26
+
27
+ [Unreleased]: https://github.com/Precision-AI-Inc/pace/compare/v0.0.1...HEAD
28
+ [0.0.1]: https://github.com/Precision-AI-Inc/pace/releases/tag/v0.0.1
@@ -0,0 +1,293 @@
1
+ # Pace — Project Standards
2
+
3
+ Apply these standards when writing, reviewing, or refactoring code in Pace. Read [docs/design.md](docs/design.md) before changing behaviour: it is the specification for the logger, the progress line format and the forecasting rules.
4
+
5
+ ---
6
+
7
+ ## Environment
8
+
9
+ - Python 3.8+ is supported; develop on 3.9+ (pre-commit needs it), managed with `python -m venv .venv` (never conda)
10
+ - Install: `pip install -e ".[dev]"` → installs all deps including pre-commit
11
+ - Register hooks once: `pre-commit install`
12
+ - CI runs the tests on 3.8 through 3.13. 3.8 runs on `ubuntu-22.04`, because `actions/setup-python` has no 3.8 build for `ubuntu-latest`.
13
+
14
+ ---
15
+
16
+ ## The rules that matter most
17
+
18
+ 1. **The core has no runtime dependencies.** `precisionai.pace` imports only the standard library. It is installed into users' training images and into other packages, and must never add to them. A framework adapter imports its framework only inside its own module, behind an extra (`[lightning]`, `[transformers]`).
19
+ 2. **The line format is a public contract.** Anything a consumer parses (the `[pace:N ...]` trailer) changes only as documented in `docs/design.md`: new optional keys within a major version, anything else is a new major version. A format change updates `docs/design.md` and the fixtures in `tests/fixtures/protocol/` in the same PR. The readable text before the trailer is for people and may change freely; never make a consumer depend on it.
20
+ 3. **Python 3.8 compatible.** See [Type hints](#type-hints) for what that rules out.
21
+ 4. **Never log secrets on the package's own initiative.** Pace never writes environment variables, configuration or credentials by itself, and labels stay short and are not repeated on every update.
22
+ 5. **Parsing is defensive.** Log lines are untrusted input. The parser bounds every size and value, never evaluates anything, and ignores (never raises on) a malformed or unsupported line.
23
+
24
+ ---
25
+
26
+ ## Project layout
27
+
28
+ ```
29
+ precisionai/pace/
30
+ core.py, _env.py, _render.py, capture.py # the logger
31
+ scopes.py # track, progress, timed, phase, plan
32
+ protocol.py # Record, the [pace:1 ...] trailer, parse_line, LineSplitter
33
+ forecast.py # ScopeForecast, JobForecast
34
+ lightning.py, transformers.py, _adapters.py # framework callbacks (extras only)
35
+ version.py # installed package version
36
+ __init__.py # re-exports only — no logic
37
+ docs/ # Sphinx (HTML + LaTeX/PDF); design.md is the specification
38
+ skills/adopt-pace/ # Claude Code skill that adds Pace to a repo; verify.py checks a log
39
+ examples/ # runnable examples
40
+ tests/ # mirrors package structure; fixtures/protocol/ holds format conformance cases
41
+ ```
42
+
43
+ `precisionai` is a fixed, namespace-only top-level package (no logic, just an SPDX header) shared by Precision AI Python projects, which is what makes `precisionai.<namespace>.*` imports consistent across them.
44
+
45
+ ---
46
+
47
+ ## pyproject.toml — canonical config
48
+
49
+ ```toml
50
+ [project]
51
+ dynamic = ["version"] # version comes from the git tag via setuptools-scm, never hardcoded
52
+ requires-python = ">=3.8"
53
+ dependencies = [] # see "The rules that matter most"
54
+
55
+ [tool.setuptools_scm]
56
+ version_scheme = "no-guess-dev"
57
+ local_scheme = "no-local-version"
58
+ fallback_version = "0.0.0"
59
+
60
+ [tool.ruff]
61
+ line-length = 120
62
+ target-version = "py38"
63
+
64
+ [tool.ruff.lint]
65
+ select = ["E","W","F","I","UP","B","SIM","N","C90","D","PT","RUF","PL","ANN","PERF","S","FA"]
66
+ ignore = [
67
+ "E501", # enforced by ruff-format
68
+ "SIM108", # ternary readability
69
+ "D100","D104", # module/package docstrings optional
70
+ "D203","D213", # pydocstyle conflicts — always ignore these two
71
+ "PLR0913","PLR2004", # arg count (progress scopes take several optional fields) + magic values in tests
72
+ "ANN401", # Any is allowed for genuinely dynamic types
73
+ ]
74
+ [tool.ruff.lint.per-file-ignores]
75
+ "**/__init__.py" = ["F401"]
76
+ "tests/**" = ["D","PLR","ANN","S"]
77
+ "docs/conf.py" = ["E402","UP031","ANN","S","FA"]
78
+
79
+ [tool.ruff.lint.pydocstyle]
80
+ convention = "numpy" # enforces NumPy docstring style
81
+
82
+ [tool.ruff.lint.mccabe]
83
+ max-complexity = 10
84
+
85
+ [tool.ruff.lint.isort]
86
+ known-first-party = ["precisionai"]
87
+
88
+ [tool.ruff.format]
89
+ quote-style = "double"
90
+ indent-style = "space"
91
+ docstring-code-format = true # formats code blocks inside docstrings
92
+
93
+ [tool.pytest.ini_options]
94
+ addopts = "--cov=precisionai --cov-report=term-missing --cov-fail-under=90"
95
+
96
+ [tool.coverage.report]
97
+ fail_under = 90
98
+ exclude_lines = ["pragma: no cover","if __name__ == .__main__.:",
99
+ "raise ImportError","except ImportError","if TYPE_CHECKING:"]
100
+
101
+ [tool.pyright]
102
+ pythonVersion = "3.8"
103
+ typeCheckingMode = "standard"
104
+ reportMissingImports = false
105
+ reportMissingModuleSource = false
106
+ ```
107
+
108
+ ---
109
+
110
+ ## pre-commit
111
+
112
+ ```yaml
113
+ repos:
114
+ - repo: https://github.com/pre-commit/pre-commit-hooks
115
+ rev: v6.0.0
116
+ hooks: [check-added-large-files (--maxkb=1800), check-yaml, check-json,
117
+ check-toml, end-of-file-fixer, trailing-whitespace,
118
+ check-merge-conflict, detect-private-key, debug-statements,
119
+ fix-byte-order-marker]
120
+
121
+ - repo: https://github.com/astral-sh/ruff-pre-commit
122
+ rev: v0.15.17
123
+ hooks: [ruff (--fix), ruff-format]
124
+
125
+ - repo: local
126
+ hooks:
127
+ - id: pyright
128
+ name: pyright
129
+ entry: python -m pyright
130
+ language: system
131
+ types: [python]
132
+ pass_filenames: false
133
+
134
+ - repo: local
135
+ hooks:
136
+ - id: pytest
137
+ entry: python -m pytest
138
+ language: system
139
+ args: [tests/, -q, --tb=short, --no-header]
140
+ always_run: true
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Code style
146
+
147
+ ### License header
148
+ - Every `.py` file starts with a two-line SPDX header, followed by a blank line before the module docstring (if any):
149
+ ```python
150
+ # Copyright 2026 Precision AI
151
+ # SPDX-License-Identifier: Apache-2.0
152
+ ```
153
+ - No "CONFIDENTIAL" or proprietary banners — this codebase is Apache 2.0 licensed; any such banner is a bug.
154
+
155
+ ### Imports
156
+ - All imports at the **top of the file** — never inside functions
157
+ - Optional framework deps (adapters only): module-level `try/except ImportError` with a flag variable
158
+ - No silent fallbacks unless mathematically equivalent (document why)
159
+ - `__init__.py` re-exports only — no logic, no comments between import blocks
160
+ - `__all__` must be **alphabetically sorted**
161
+
162
+ ```python
163
+ # optional dep pattern (adapter modules only — never in the core)
164
+ try:
165
+ import lightning.pytorch as pl # type: ignore[import]
166
+ _LIGHTNING_AVAILABLE = True
167
+ except ImportError:
168
+ _LIGHTNING_AVAILABLE = False
169
+
170
+ # inside the class/function that needs it
171
+ if not _LIGHTNING_AVAILABLE:
172
+ raise ImportError("lightning is required: pip install precisionai-pace[lightning]") from None
173
+ ```
174
+
175
+ ### Docstrings
176
+ - **NumPy style** on all public functions, classes, and modules
177
+ - Module docstrings: plain English, no prefixes (no P0/P1/P2, no "original", no labels)
178
+ - One-line summary in **imperative mood** ("Compute …", "Return …", "Save …")
179
+ - Blank line between summary and extended description (D205)
180
+
181
+ ### Type hints
182
+ - Required on **all** function signatures (public and private) — enforced by ruff (`ANN`) and pyright
183
+ - Every module with annotations starts with `from __future__ import annotations` (enforced by ruff `FA`). With it, `X | Y` and `list[int]` are fine **in annotations** on 3.8.
184
+ - **Outside annotations**, code runs on 3.8: no `X | Y` in `isinstance`, casts or type aliases evaluated at runtime, no `match`, no `str.removeprefix`, no parenthesised context managers, no `dataclass(slots=True)` or `kw_only`. Use `isinstance(x, (A, B))`, `typing.Union`/`Optional` in runtime aliases, and `typing.TYPE_CHECKING` for import-only types.
185
+ - Use `Any` from `typing` for genuinely dynamic types — don't use `object` when methods will be called on it
186
+ - pyright config lives in `[tool.pyright]` in `pyproject.toml` — never pass type-checker flags inline
187
+
188
+ ### Comments
189
+ - Only when the **why** is non-obvious
190
+ - No section-divider comments that describe what the code already says
191
+ - No cryptic labels, no TODO/FIXME without a ticket reference
192
+
193
+ ### Exception handling
194
+ - Always `raise X from err` or `raise X from None` inside `except` blocks (B904)
195
+ - Logging and progress calls never raise into user code because of a formatting or I/O problem; they degrade (drop the record, fall back to plain text) instead
196
+
197
+ ### General
198
+ - `len()` returns `int` — never `int(len(...))`
199
+ - Loop variables not used in the body → rename to `_`
200
+ - `assert a and b` in tests → split into separate asserts
201
+ - `@pytest.fixture` not `@pytest.fixture()`
202
+ - `pytest.raises` always includes `match=` parameter
203
+ - No `# type: ignore[attr-defined]` when `Any` already covers the attribute
204
+ - Rates and intervals use `time.monotonic()`; wall-clock time is only for the printed timestamp
205
+
206
+ ---
207
+
208
+ ## README is the PyPI page
209
+
210
+ `README.md` is published as the PyPI project description, where relative paths do not resolve. Every link and image in it is an absolute `https://github.com/Precision-AI-Inc/pace/blob/main/...` or `https://raw.githubusercontent.com/Precision-AI-Inc/pace/main/...` URL (enforced by `tests/test_readme.py`). Those URLs only load for anonymous visitors once the repository is public.
211
+
212
+ ---
213
+
214
+ ## Docs (Sphinx)
215
+
216
+ ```
217
+ docs/
218
+ conf.py # version from git tag, logo, LaTeX/fancyhdr, enumitem fix
219
+ index.rst # toctrees: user guide, reading output, reference
220
+ design.md # the specification — update it with any behaviour or format change
221
+ modules.rst # autodoc for all public submodules
222
+ requirements.txt # sphinx, sphinx-rtd-theme, myst-parser, sphinx-autodoc-typehints
223
+ Makefile # make html | make latexpdf | make clean
224
+ assets/logo.png
225
+ ```
226
+
227
+ - `conf.py` copies root `README.md` → `docs/readme.md` at build time
228
+ - Version read from `git describe --tags --exact-match`, falls back to `0.0.0`
229
+
230
+ ---
231
+
232
+ ## Testing
233
+
234
+ - Mirror package structure: `tests/test_<module>.py`
235
+ - Shared fixtures in `tests/conftest.py`
236
+ - 90% coverage hard minimum — enforced by pytest and pre-commit
237
+ - Format conformance cases live in `tests/fixtures/protocol/` as input lines plus expected parse results; consumers run the same files
238
+ - Tests that depend on time use an injected clock, never `sleep`
239
+ - Integration tests marked `@pytest.mark.integration` and excluded from default runs
240
+
241
+ ---
242
+
243
+ ## Repository files
244
+
245
+ Besides the source layout above, the repository carries:
246
+
247
+ ```
248
+ .gitattributes # normalize line endings to LF; declare binary assets
249
+ CHANGELOG.md # Keep a Changelog format + Semantic Versioning
250
+ CODE_OF_CONDUCT.md # Contributor Covenant v2.1
251
+ MANIFEST.in # sdist packaging — include docs/license/changelog, exclude tests/examples
252
+ .github/
253
+ dependabot.yml # weekly pip + github-actions update checks
254
+ ISSUE_TEMPLATE/
255
+ bug_report.yml
256
+ feature_request.yml
257
+ config.yml # blank_issues_enabled: false + link to SECURITY.md
258
+ PULL_REQUEST_TEMPLATE.md
259
+ workflows/
260
+ ci.yml # dispatches to pre-commit.yml + unit-test.yml
261
+ pre-commit.yml
262
+ unit-test.yml
263
+ release.yml # tag push → build, PyPI publish, GitHub Release
264
+ ```
265
+
266
+ ## Releasing
267
+
268
+ - Versions are **never hardcoded** — `setuptools-scm` derives the package version from the current git tag (see the `pyproject.toml` block above). Tag with `vX.Y.Z`.
269
+ - Update `CHANGELOG.md` under `[Unreleased]` as you go; move those entries to a new `## [X.Y.Z] - YYYY-MM-DD` section when cutting a release.
270
+ - Pushing a `v*.*.*` tag triggers `.github/workflows/release.yml`: runs the full test matrix, builds the sdist/wheel, verifies the built version matches the tag, publishes to PyPI via trusted publishing (`id-token: write`, no stored API tokens), and creates a GitHub Release with generated notes.
271
+ - CI checkout steps that build from git history (release builds, docs version detection) must use `fetch-depth: 0` — a shallow checkout has no tags for `setuptools-scm` or `git describe` to find.
272
+
273
+ ---
274
+
275
+ ## What to avoid
276
+
277
+ | Pattern | Instead |
278
+ |---|---|
279
+ | A new entry in `dependencies` | Put it behind an extra, imported only by the adapter module |
280
+ | Parsing the readable part of a progress line | Parse only the `[pace:N ...]` trailer |
281
+ | Changing or removing a trailer key in place | New optional key, or a new major version (see `docs/design.md`) |
282
+ | `isinstance(x, A \| B)`, `match`, other 3.10+ runtime syntax | `isinstance(x, (A, B))` and 3.8-compatible equivalents |
283
+ | `time.time()` for rates or intervals | `time.monotonic()` |
284
+ | `int(len(x))` | `len(x)` |
285
+ | `assert a and b` (tests) | two separate asserts |
286
+ | `@pytest.fixture()` | `@pytest.fixture` |
287
+ | `pytest.raises(ValueError)` | `pytest.raises(ValueError, match="…")` |
288
+ | `raise X` inside except | `raise X from None` or `raise X from err` |
289
+ | Deferred imports inside functions | Module-level try/except with flag |
290
+ | Cryptic prefixes (P0–P4, "original") | Plain descriptive names |
291
+ | `# type: ignore[attr-defined]` on `Any` | Remove — redundant |
292
+ | `# noqa` suppression | Fix the underlying issue |
293
+ | Silent fallback for optional dep | Raise `ImportError` with install hint |
@@ -0,0 +1,47 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ - Demonstrating empathy and kindness toward other people
14
+ - Being respectful of differing opinions, viewpoints, and experiences
15
+ - Giving and gracefully accepting constructive feedback
16
+ - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ - Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ - The use of sexualized language or imagery, and sexual attention or advances of any kind
22
+ - Trolling, insulting or derogatory comments, and personal or political attacks
23
+ - Public or private harassment
24
+ - Publishing others' private information, such as a physical or email address, without their explicit permission
25
+ - Other conduct which could reasonably be considered inappropriate in a professional setting
26
+
27
+ ## Enforcement Responsibilities
28
+
29
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
32
+
33
+ ## Scope
34
+
35
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces.
36
+
37
+ ## Enforcement
38
+
39
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at michael@precision.ai. All complaints will be reviewed and investigated promptly and fairly.
40
+
41
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
42
+
43
+ ## Attribution
44
+
45
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1.
46
+
47
+ [homepage]: https://www.contributor-covenant.org
@@ -0,0 +1,79 @@
1
+ # Contributing
2
+
3
+ Thank you for your interest in contributing to Pace.
4
+
5
+ ## Setup
6
+
7
+ Requires Python 3.8+ to use, and Python 3.9+ to run the pre-commit hooks.
8
+
9
+ ```bash
10
+ git clone <repo-url>
11
+ cd pace
12
+
13
+ python -m venv .venv
14
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
15
+
16
+ pip install -e ".[dev]"
17
+ pre-commit install
18
+ ```
19
+
20
+ `pip install -e ".[dev]"` installs all dependencies including test tooling and pre-commit. `pre-commit install` registers the hooks so they run automatically on every commit.
21
+
22
+ ## Making changes
23
+
24
+ 1. Create a branch from `main`.
25
+ 2. Make your changes.
26
+ 3. Add or update tests — coverage must remain at or above 90%. Code must run on Python 3.8, and the core package must not gain a runtime dependency.
27
+ 4. Commit. Pre-commit hooks run automatically and will block the commit if any check fails.
28
+
29
+ If a hook auto-fixes files (ruff lint/format), stage the changes and commit again.
30
+
31
+ ## Pre-commit hooks
32
+
33
+ | Hook | What it checks |
34
+ |---|---|
35
+ | File hygiene | Large files (>1800 KB), trailing whitespace, merge conflicts, private keys, debug statements, BOM removal |
36
+ | `ruff` | Linting and import sorting (auto-fix); includes `ANN` rules that enforce PEP 484 annotations |
37
+ | `ruff-format` | Code formatting (auto-fix) |
38
+ | `pyright` | Static type checking (pylance engine) — config in `[tool.pyright]` in `pyproject.toml` |
39
+ | `pytest` | Full test suite with ≥ 90% coverage |
40
+
41
+ Run all hooks manually without committing:
42
+
43
+ ```bash
44
+ pre-commit run --all-files
45
+ ```
46
+
47
+ ## Code style
48
+
49
+ - **Formatter / linter:** ruff (`line-length = 120`, Python 3.8 target).
50
+ - **Type hints:** all functions (public and private) must have complete PEP 484 type annotations. Enforced at lint time by ruff (`ANN` rules) and statically by pyright. `Any` is allowed for genuinely dynamic types; explicit `Any` is preferred over `object` when methods will be called on a value.
51
+ - **Docstrings:** NumPy style for all public functions, classes, and modules.
52
+ - **Comments:** only where the _why_ is non-obvious. No inline narration of what the code does.
53
+
54
+ See [CLAUDE.md](CLAUDE.md) for the full standard.
55
+
56
+ ## Tests
57
+
58
+ ```bash
59
+ pytest # run all tests with coverage report
60
+ pytest tests/test_version.py # run a specific file
61
+ pytest -k "version" # run tests matching a pattern
62
+ ```
63
+
64
+ Tests live in `tests/` and mirror the package structure. The coverage threshold (90%) is enforced both by `pytest` directly and by the pre-commit hook.
65
+
66
+ ## Pull requests
67
+
68
+ - Keep PRs focused — one logical change per PR.
69
+ - A change to the progress line format must update `docs/design.md` and the protocol fixtures in the same PR.
70
+ - Write a clear description of what changed and why.
71
+ - All pre-commit hooks must pass before requesting review.
72
+
73
+ ## License
74
+
75
+ By contributing, you agree that your contributions are licensed under the Apache License, Version 2.0.
76
+
77
+ ## Code of Conduct
78
+
79
+ This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md).