Build/pypi readiness - #2
Merged
Merged
Conversation
…to Python 3.11+ Adds docs/pypi-publication-readiness-plan.md (9-phase plan for the first public PyPI release, v0.1.1) and resolves three of its Phase 1 decisions: 1. Removed the 7 camelCase backward-compatibility wrappers (getMidFlameWS, getFlameLength, getFlameHeight, getFlameTilt, getFlameResidenceTime, getFlameDepth, flameComponent_ArrayMultiprocessing) and the _deprecated_alias factory from core.py, and their re-exports from __init__.py. The package has never been published to PyPI and has no known external consumers of the camelCase names, so there's nothing to protect by deprecating them further. Replaces tests/unit/test_deprecated_aliases.py (9 tests) with a new tests/unit/test_public_api.py (1 test) that keeps the one still-relevant assertion: __all__ contains exactly the 7 snake_case public names. Updates docs/TEST_SUITE_DESCRIPTION.md (122 -> 114 tests; unit 110 -> 102). 2. Narrowed supported Python to `>=3.11` (from `>=3.9`), a deliberate choice to stop carrying 3.9/3.10. Updates pyproject.toml `requires-python`, README.md's stated floor, and regenerates uv.lock (drops all 3.9/3.10 resolution markers and wheels). 3. Raised the numpy floor to `>=1.23.2` (from `>=1.20`) to match -- it's the oldest numpy release with Python 3.11 wheels. Validated directly rather than inferred: `uv venv --python 3.11` + `uv pip install -e ".[test]" "numpy==1.23.2"` with an explicit version assertion -- 114/114 pass. Also confirmed at numpy 2.4.6 (py3.11) and 2.5.2 (py3.14, newest available locally). No upper bound added. Full suite verified via `uv sync` + `uv run pytest`: 114/114 pass.
…dd CITATION.cff
Resolves the readiness plan's Phase 2 documentation items:
1. Rewrote docs/CODEBASE.md against the current repository. It previously
described the pre-refactor layout (a monolithic flame_components.py),
the camelCase-first API, an ArcGIS raster variant presented as a shipped
implementation, and several defects that were fixed in earlier sessions.
Now reflects src/flame_components/core.py + __init__.py, the snake_case
only API (no aliases), archive/flame_components_arcgisRaster.py marked
explicitly as unshipped/unmaintained (excluded from the sdist), and only
gotchas that are still true of the current code.
2. Expanded README.md:
- documented the flame-components (PyPI) vs flame_components (import)
name difference;
- made the multiprocessing example self-contained and executable --
defines real numpy arrays inline and shows np.concatenate(blocks) to
get a single result array back;
- verified both the basic usage example and the multiprocessing example
actually run correctly via `uv run python`;
- added an API Reference section covering all 7 public functions: units,
model-specific required arguments, return shapes, and the
TypeError/ValueError conventions;
- added a Scientific References section (author/year per function,
sourced from each function's docstring, with a note to verify full
bibliographic detail before citing formally);
- added a Support and Issue Reporting section listing what's needed to
reproduce a numerical discrepancy.
3. Added CITATION.cff at the repo root (title, author, repository-code,
license -- no fabricated DOI or unverified bibliographic details).
Full suite verified: 114/114 pass.
Resolves the readiness plan's Phase 3 metadata items in pyproject.toml:
1. Added [project.urls]: Homepage, Source, Issue Tracker, Release Notes
(GitHub Releases -- no maintained changelog claimed), and Documentation
(points at the README on GitHub, since there's no separate docs site).
2. Added classifiers for every Python version actually verified this
session (3.11, 3.12, 3.13, 3.14 -- each installed fresh and run through
the full suite, not just declared), plus Development Status :: 4 - Beta
and Intended Audience :: Science/Research.
3. Modernized license metadata to SPDX: `license = "MIT"` +
`license-files = ["LICENSE"]`, replacing the old `license = {file =
"LICENSE"}` form and dropping the now-redundant "License :: OSI
Approved :: MIT License" classifier. Verified via a real build: the
wheel's METADATA shows `License-Expression: MIT` and `twine check`
passes on both the wheel and sdist.
4. Author/maintainer contact info: left as name-only, no email -- explicit
user decision.
5. Confirmed via an actual build+install (not just reading pyproject.toml):
the wheel's only non-extra Requires-Dist is numpy>=1.23.2 (pytest is
extra == 'test' only), and __version__ + __all__ resolve correctly in a
freshly `uv pip install`-ed wheel in an isolated venv.
Keywords and short description reviewed and confirmed accurate; no change
needed.
Full suite verified: 114/114 pass.
Planning docs (docs/*-plan.md) are working references for the readiness effort, not part of the public-facing repo -- they shouldn't ship to origin. Untracks docs/pypi-publication-readiness-plan.md (kept on disk, just no longer committed) and ignores the docs/*-plan.md pattern going forward, which also covers docs/test-suite-robustness-improvement-plan.md (already untracked).
…ob, smoke test Resolves the readiness plan's Phase 4 compatibility/quality-gate items in .github/workflows/tests.yml: 1. Bumped astral-sh/setup-uv@v3 -> @v10 (latest) and actions/checkout@v4 -> @v7 (stale, zero-risk to update alongside). 2. Replaced the single ubuntu/py3.12 job with a matrix covering the full claimed Python range: 3.11, 3.12, 3.13, 3.14 on ubuntu-latest, plus a Windows + Python 3.12 leg (multiprocessing coverage -- FuelAnalyst runs on Windows). fail-fast: false so one failing leg doesn't hide others. 3. Added a minimum-dependency job: Python 3.11 + numpy==1.23.2 pinned exactly (not >=1.23.2), with an explicit version-assert step so a resolver can't silently substitute a newer NumPy and defeat the test. 4. No separate "latest NumPy" job needed -- the regular matrix jobs already use `uv sync` with no NumPy pin, so they resolve the newest-compatible NumPy per Python version at CI run time. 5. All jobs now run `pytest tests/ -v --tb=long -W error` (unexpected warnings become failures; tests using pytest.warns(...) are unaffected since that context manager isolates its own warning capture). 6. Added scripts/smoke_test.py: a standalone script that only imports the installed flame_components package (no repo import) -- checks __version__, verifies __all__ is exactly the 7 expected snake_case names and each is callable, and runs one scalar call, one array call, and one multiprocessing call. Runs in every CI job after install; reusable as-is for Phase 5/7/8's build-artifact verification steps. Verified before trusting the YAML: simulated both the regular matrix job (Python 3.11) and the minimum-dependency job end-to-end locally -- real venv, real install, real pytest -W error run, real smoke test run. All pass. Branch-protection enforcement of these checks is Phase 6, not this commit. Full suite verified: 114/114 pass.
…ld artifacts
Resolves the readiness plan's Phase 5 build/artifact-inspection items. Only
one code change resulted (the rest was verification against a clean
clone, not committed):
Fixed a real relative-link issue in README.md: the License section linked
`[LICENSE](LICENSE)`, a relative path Warehouse (PyPI) isn't guaranteed to
resolve for `[project.urls]`-based metadata (automatic relative-link
rewriting was reliably tied to the legacy `Home-page` field, not the
modern Project-URL fields). Changed to an absolute GitHub URL, which
renders identically on GitHub and is guaranteed to work on PyPI.
Verification performed (no other files changed):
- Built from a genuinely clean git clone of this branch (not the working
directory) with full history/tags -- confirmed docs/*-plan.md, .idea/,
and other ignored files are correctly absent from what a real build
would see.
- `uv sync --locked --all-extras --dev` + `uv run pytest tests/ -v`
(114/114) + `uv build --no-sources`.
- `twine check` PASSED on both the wheel and sdist.
- Inspected full file listings of both artifacts -- wheel has only package
code + metadata + license; sdist correctly excludes archive/, plan
docs, caches, and IDE files.
- Built a wheel from an independently re-extracted copy of the sdist and
diffed it byte-for-byte (SHA-256 per file) against the original wheel:
identical, confirming the sdist->wheel path is truly reproducible.
- Installed the wheel into one fresh venv and the sdist into a second,
separate fresh venv, and ran scripts/smoke_test.py from a directory
with no repo on PYTHONPATH in each -- both passed.
- Re-verified twine check and README.md's raw-byte UTF-8 validity after
the link fix.
Recorded (not the real release artifact -- hashes will differ once built
from the tagged v0.1.1 commit in Phase 8):
flame_components-0.1.1.dev7+ge5aea5fbc-py3-none-any.whl
sha256:d4f225ea6610df38fbc04eed6204f18f74881f65c39a1e0dae24d22bc046bfac
flame_components-0.1.1.dev7+ge5aea5fbc.tar.gz
sha256:593cc642fdc2ecb89c5bfaadc6fb4c759b513fe11aeecfd01ba4867f02225e29
Full suite verified: 114/114 pass.
…e procedure
Resolves the readiness plan's Phase 6 items that don't require PyPI/GitHub
account access (three items do and are called out below for the user):
1. Added .github/workflows/release.yml: triggers only on a deliberate,
human-published GitHub Release (release: types: [published]), never a
bare tag push.
- `build` job (isolated): full test suite -> `uv build` -> `twine
check` -> installs the built wheel into a fresh venv and runs
scripts/smoke_test.py -> uploads dist/ as a workflow artifact ->
attaches those exact files to the GitHub Release via `gh release
upload`.
- `publish-testpypi`/`publish-pypi` jobs each download that same
artifact (never rebuild) and run pypa/gh-action-pypi-publish@release/v1
-- no long-lived API token, OIDC Trusted Publishing only. Which one
runs is decided by the Release's `prerelease` flag: checked (an rcN
tag) -> TestPyPI, unchecked (a real version tag) -> PyPI.
- `id-token: write` is granted only on the two publish jobs (verified
via a parsed-YAML permissions dump); `build` gets `contents: write`
only, for the release-upload step.
- Bumped actions/upload-artifact and download-artifact to @v7 (latest)
while adding them.
2. Added docs/RELEASING.md (tracked reference doc describing the ongoing
process, not a plan): one-time Trusted Publishing/GitHub-environment/
branch-protection setup, the cut-a-release steps, what belongs in
release notes vs. the private vault, and recovery options (yank vs. new
version vs. safe-to-repoint-if-nothing-published-yet).
Needs the user directly, not automatable from a local session:
- Create `pypi`/`testpypi` GitHub environments, with a required reviewer
on `pypi`.
- Register a pending Trusted Publisher on pypi.org and test.pypi.org
(workflow filename `release.yml`, environment names `pypi`/`testpypi`
matching the workflow exactly).
- Protect `master`, requiring the `Tests` workflow before merge.
Full suite verified: 114/114 pass (no production code touched this phase).
CI failed on the PR: "Unable to resolve action astral-sh/setup-uv@v10, unable to find version v10" on every Python 3.11-3.14 matrix job. Unlike actions/checkout or actions/upload-artifact, astral-sh/setup-uv does not publish a floating major-version tag (no "v10" ref exists in that repo -- only exact tags like v10.0.1, v10.0.0, v9.0.0). Pinning it the same way as GitHub's own actions was the mistake. Fixed all three references (tests.yml's two jobs, release.yml's build job) to the exact tag astral-sh/setup-uv@v10.0.1. While fixing this, re-verified every other action reference in both workflow files against the actual upstream repos (not just assumed): actions/checkout@v7, actions/upload-artifact@v7, actions/download-artifact@v7, and pypa/gh-action-pypi-publish@release/v1 all confirmed to exist as real refs. Full suite verified: 114/114 pass (no test code affected -- this is a CI-config-only fix).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Executes Phases 1–6 of
docs/pypi-publication-readiness-plan.md(local reference doc,not part of this diff) in preparation for the first public PyPI release of
flame-componentsasv0.1.1. Covers release policy, documentation, package metadata,CI compatibility, build-artifact verification, and a secure publishing workflow.
Full test suite: 114/114 passing throughout.
Breaking changes (pre-1.0, no PyPI release exists yet)
getMidFlameWS,getFlameLength,getFlameHeight,getFlameTilt,getFlameResidenceTime,getFlameDepth,flameComponent_ArrayMultiprocessing) entirely, rather than carrying them through adeprecation cycle. The package has never been published and has no known external
consumers of the camelCase names, so there's nothing to protect.
>=3.11(from>=3.9) — a deliberate choiceto stop carrying 3.9/3.10.
>=1.23.2(from>=1.20) to match — the oldest numpyrelease with Python 3.11 wheels. Validated directly (not inferred) on the actual floor
and multiple newer versions; still unbounded above.
Phase 1 — Release policy and package identity
v0.1.1(not re-pointingv0.1.0, since packagingchanges already merged after that tag).
Phase 2 — Project documentation
docs/CODEBASE.mdagainst the currentsrc/layout, snake_case-only API, andremoved stale references to fixed bugs and the unshipped ArcGIS variant.
README.md: distribution-vs-import-name note, a verified self-contained/executable multiprocessing example, an API Reference section for all 7 public
functions, a Scientific References section, and a Support/Issue-Reporting section.
CITATION.cff.Phase 3 — Package metadata
[project.urls](Homepage, Source, Issue Tracker, Release Notes, Documentation).(3.11–3.14), plus Development Status / Intended Audience classifiers.
license = "MIT"+license-files), dropping thenow-redundant classifier. Verified via a real build:
License-Expression: MIT,twine checkpasses.numpy);pytestremains test-only.Phase 4 — CI compatibility and quality gates
ubuntu-latest, plus a Windows + Python 3.12 leg (multiprocessing coverage).minimum-dependencyjob pinning Python 3.11 +numpy==1.23.2exactly, with aversion-assert step.
-W error(unexpected warnings fail the build).scripts/smoke_test.py: a standalone script that only imports the installedpackage (no repo import) and exercises
__version__,__all__, and one scalar/array/multiprocessing call each. Runs in every CI job and is reused by the release workflow.
astral-sh/setup-uvandactions/checkoutto current major versions.Phase 5 — Build and artifact verification
twine checkpasses onboth the wheel and sdist.
include/exclude list.
byte-for-byte identical (SHA-256 per file) to the directly-built wheel.
smoke test in each, outside the repo.
(
[LICENSE](LICENSE)), which PyPI isn't guaranteed to resolve correctly under modern[project.urls]metadata. Changed to an absolute GitHub URL.Phase 6 — Secure publishing
.github/workflows/release.yml: triggers only on a human-published GitHubRelease (never a bare tag push). An isolated
buildjob runs the full suite, buildsand validates distributions, installs the built wheel into a fresh environment and
smoke-tests it, then attaches the exact files to the GitHub Release. Separate
publish-testpypi/publish-pypijobs (gated by the Release's prerelease flag) downloadthat same artifact and publish via
pypa/gh-action-pypi-publishusing OIDC TrustedPublishing — no long-lived API token.
id-token: writeis scoped to only those two jobs.docs/RELEASING.md: the ongoing release procedure, one-time setup steps, andrecovery guidance (PyPI releases can't be replaced — yank or ship a new version).
Not yet done (needs repo/account access this session doesn't have):
pypi/testpypiGitHub environments (with a required reviewer onpypi).workflow
release.yml, matching environment names.masterto require theTestsworkflow.These are spelled out in
docs/RELEASING.md's "One-time setup" section and need to happenbefore
release.ymlcan succeed — GitHub only recognizesrelease-triggered workflowsfrom the default branch, so this also couldn't be rehearsed before this merge.
Not in this PR
Phases 7–9 (TestPyPI rehearsal, production release, FuelAnalyst downstream adoption) are
next, after the account-side setup above and this merge.
Test plan
uv run pytest tests/ -v— 114/114 passuv build+twine check dist/*— both artifacts passindependently of the source tree
(not yet executed end-to-end — blocked on the account-side setup above)