fix(python-sdk): Use README.md as single source of truth, fix CI compile#697
Conversation
- Speakeasy generates readme = "README-PYPI.md" in pyproject.toml but does not emit that file, causing poetry build/install to fail in CI. - Use README.md as the only readme in repo; add patch_pyproject_readme.py to fix pyproject after generation (run via compileCommand in workflow). - Publish: prepare_readme.py + temporary pyproject switch to README-PYPI.md only at publish time for PyPI absolute links; remove README-PYPI.md from repo and ignore in .gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Updates the generated Outpost Python SDK packaging workflow so poetry build/install succeeds in CI by making README.md the default package README, while still allowing a link-rewritten README to be used only for PyPI publishing.
Changes:
- Switch
pyproject.tomlto useREADME.mdand remove committedREADME-PYPI.md(now generated only at publish time). - Add a post-generation patch script and wire it into Speakeasy’s
compileCommandbeforepoetry build. - Update publish script to generate
README-PYPI.mdand temporarily pointpyproject.tomlat it for the publish build.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
sdks/outpost-python/pyproject.toml |
Uses README.md as the package readme to prevent build failures when README-PYPI.md is absent. |
sdks/outpost-python/scripts/patch_pyproject_readme.py |
New helper to patch Speakeasy-generated pyproject.toml back to README.md before compile/build. |
.speakeasy/workflow.yaml |
Overrides Python target compile command to run the patch before poetry build. |
sdks/outpost-python/scripts/publish.sh |
Generates README-PYPI.md and switches pyproject.toml to use it for publishing. |
sdks/outpost-python/README-PYPI.md |
Removes the file from the repo (generated only at publish time). |
sdks/outpost-python/.gitignore |
Ignores the generated README-PYPI.md. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pyrightconfig.json | ||
| # README-PYPI.md is committed as a temporary workaround for Speakeasy compile; overwritten by scripts/prepare_readme.py at publish. | ||
| README-PYPI.md | ||
| .DS_Store |
There was a problem hiding this comment.
.gitignore contains a duplicate .DS_Store entry. Removing the duplicate reduces noise and makes the ignore list easier to maintain.
| .DS_Store |
| poetry run python scripts/prepare_readme.py | ||
|
|
||
| # Point pyproject at the link-rewritten readme for the publish build | ||
| sed -i.bak 's/readme = "README.md"/readme = "README-PYPI.md"/' pyproject.toml | ||
| poetry publish --build --skip-existing | ||
| rm -f pyproject.toml.bak |
There was a problem hiding this comment.
publish.sh edits pyproject.toml to point at README-PYPI.md but never restores it back to README.md. After a local publish (or a failed publish), the working tree will be left in a state where normal builds/tests may fail unless README-PYPI.md is present. Consider restoring pyproject.toml from the backup on exit (e.g., via a trap) and/or explicitly switching it back to README.md after poetry publish completes.
| poetry run python scripts/prepare_readme.py | ||
|
|
||
| # Point pyproject at the link-rewritten readme for the publish build | ||
| sed -i.bak 's/readme = "README.md"/readme = "README-PYPI.md"/' pyproject.toml |
There was a problem hiding this comment.
The sed replacement assumes the pyproject line is exactly readme = "README.md". If the generated/edited TOML uses different whitespace/quotes or already has README-PYPI.md, this command will silently do nothing and the publish build may use the wrong README. Consider making this replacement resilient (match the readme key regardless of current value/spacing) and fail fast if no change was applied.
| sed -i.bak 's/readme = "README.md"/readme = "README-PYPI.md"/' pyproject.toml | |
| sed -i.bak -E 's/^[[:space:]]*readme[[:space:]]*=[[:space:]]*".*"/readme = "README-PYPI.md"/' pyproject.toml | |
| if cmp -s pyproject.toml pyproject.toml.bak; then | |
| echo "Error: failed to update readme in pyproject.toml" >&2 | |
| exit 1 | |
| fi |
| #!/usr/bin/env bash | ||
| # README.md is the source of truth. For PyPI we need absolute links, so we | ||
| # generate README-PYPI.md and point pyproject at it only for this build. | ||
| export POETRY_PYPI_TOKEN_PYPI=${PYPI_TOKEN} |
There was a problem hiding this comment.
export POETRY_PYPI_TOKEN_PYPI=${PYPI_TOKEN} is unquoted and does not guard against an unset token. If PYPI_TOKEN is empty/unset, the script will attempt to publish without credentials (and may be confusing to debug). Consider using a safer pattern that errors when the token is missing and preserves any special characters in the token value.
| export POETRY_PYPI_TOKEN_PYPI=${PYPI_TOKEN} | |
| : "${PYPI_TOKEN:?PYPI_TOKEN environment variable must be set}" | |
| export POETRY_PYPI_TOKEN_PYPI="${PYPI_TOKEN}" |
| PYPROJECT = "pyproject.toml" | ||
| OLD = 'readme = "README-PYPI.md"' | ||
| NEW = 'readme = "README.md"' |
There was a problem hiding this comment.
This script patches pyproject.toml using an exact string match (OLD = 'readme = "README-PYPI.md"'). If Speakeasy changes whitespace/quoting or uses the table form for readme, the patch will fail CI. Consider matching the readme key more flexibly (e.g., regex on the assignment) so the patch is resilient to generator formatting changes.
Summary
Speakeasy's Python generator sets
readme = "README-PYPI.md"inpyproject.tomlbut does not generate that file, sopoetry buildandpoetry installfail in CI.This change makes README.md the single source of truth for the SDK in the repo and at build/test time; README-PYPI.md is only used ephemerally at publish time for PyPI (absolute links).
Changes
readme = "README.md"(so build/test work after generation).readme = "README-PYPI.md"withreadme = "README.md"inpyproject.tomlafter generation. Idempotent; run before compile in CI.compileCommandforoutpost-pythonset topython scripts/patch_pyproject_readme.py && poetry buildso the patch runs before the default compile step during SDK generation.prepare_readme.py(creates README-PYPI.md), temporarily pointpyproject.tomlat README-PYPI.md viased, runpoetry publish --build --skip-existing, then remove backup. PyPI still gets link-rewritten description.Testing
compileCommand; patch runs first sopoetry buildsees README.md.publish.shbuilds with README-PYPI.md only for the publish artifact.Made with Cursor