From 807aefa6c2590480dfc63e49afb3a5249925b3eb Mon Sep 17 00:00:00 2001 From: Phil Leggetter Date: Wed, 11 Feb 2026 20:02:59 +0000 Subject: [PATCH] fix(python-sdk): use checked-in README-PYPI.md so build succeeds after generation - Add README-PYPI.md (copy of README.md) and protect it in .genignore so Speakeasy generation does not remove it; pyproject.toml points at it. - Remove patch_pyproject_readme.py; no longer needed. - Simplify publish.sh: run prepare_readme.py then poetry publish (no sed). - Point pyproject.toml at README-PYPI.md; remove README-PYPI.md from .gitignore. - Update workflow and contributing docs. Co-authored-by: Cursor --- .speakeasy/workflow.lock | 1 - .speakeasy/workflow.yaml | 6 +- contributing/sdks.md | 12 + sdks/outpost-python/.genignore | 3 + sdks/outpost-python/.gitignore | 1 - sdks/outpost-python/README-PYPI.md | 579 ++++++++++++++++++ sdks/outpost-python/pyproject.toml | 2 +- .../scripts/patch_pyproject_readme.py | 42 -- sdks/outpost-python/scripts/publish.sh | 7 +- 9 files changed, 600 insertions(+), 53 deletions(-) create mode 100644 sdks/outpost-python/.genignore create mode 100644 sdks/outpost-python/README-PYPI.md delete mode 100644 sdks/outpost-python/scripts/patch_pyproject_readme.py diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index c3b756f4a..bc7b8c23e 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -74,7 +74,6 @@ workflow: target: python source: Outpost API (Python) output: ./sdks/outpost-python - compileCommand: "python scripts/patch_pyproject_readme.py && poetry build" publish: pypi: token: $pypi_token diff --git a/.speakeasy/workflow.yaml b/.speakeasy/workflow.yaml index 78bbbf34a..497aed0a7 100644 --- a/.speakeasy/workflow.yaml +++ b/.speakeasy/workflow.yaml @@ -33,9 +33,9 @@ targets: target: python source: Outpost API (Python) output: ./sdks/outpost-python - # Override: Speakeasy generates readme = "README-PYPI.md" but does not emit that file. - # We use README.md as the single source of truth; patch pyproject after generation. - compileCommand: "python scripts/patch_pyproject_readme.py && poetry build" + # Speakeasy sets readme = "README-PYPI.md" but does not generate it. We check in + # README-PYPI.md and list it in .genignore so the file survives generation and build succeeds. + # prepare_readme.py overwrites it at publish time with link-rewritten content for PyPI. publish: pypi: token: $pypi_token diff --git a/contributing/sdks.md b/contributing/sdks.md index 3c1a4dfb4..e5cdcaced 100644 --- a/contributing/sdks.md +++ b/contributing/sdks.md @@ -358,6 +358,18 @@ If publication fails: > **Note**: This section is for advanced use cases. SDK building and testing is automatically handled in CI/CD when PRs are created. You typically only need this for debugging or local development of the SDKs themselves. +### Replicating the Python SDK generation locally (same as CI) + +The GitHub Action runs the **Speakeasy CLI** with your `.speakeasy/workflow.yaml`. To use the same tooling and workflow locally (including the compile step): + +1. Install the [Speakeasy CLI](https://speakeasy.com/docs/speakeasy-reference/cli/getting-started). +2. Set `SPEAKEASY_API_KEY` (same secret as in the repo). +3. From the **repo root** run: + ```bash + speakeasy run -t outpost-python + ``` + This runs the same workflow as CI: generation into `sdks/outpost-python`, then the compile step (e.g. `poetry build`). There is no other way to replicate the CI setup locally without pushing and triggering the workflow. + While the CI/CD pipeline handles SDK generation, you can build and test locally if needed: ### Go SDK diff --git a/sdks/outpost-python/.genignore b/sdks/outpost-python/.genignore new file mode 100644 index 000000000..98b4da2f7 --- /dev/null +++ b/sdks/outpost-python/.genignore @@ -0,0 +1,3 @@ +# Checked-in so build succeeds (Speakeasy sets readme = "README-PYPI.md" but does not generate it). +# prepare_readme.py overwrites this at publish time with link-rewritten content for PyPI. +/README-PYPI.md diff --git a/sdks/outpost-python/.gitignore b/sdks/outpost-python/.gitignore index cbb934331..b06722451 100644 --- a/sdks/outpost-python/.gitignore +++ b/sdks/outpost-python/.gitignore @@ -9,7 +9,6 @@ __pycache__/ .python-version .DS_Store pyrightconfig.json -README-PYPI.md .DS_Store **/.speakeasy/temp/ **/.speakeasy/logs/ diff --git a/sdks/outpost-python/README-PYPI.md b/sdks/outpost-python/README-PYPI.md new file mode 100644 index 000000000..5545571d0 --- /dev/null +++ b/sdks/outpost-python/README-PYPI.md @@ -0,0 +1,579 @@ +# Outpost Python SDK + +Developer-friendly & type-safe Python SDK specifically catered to leverage the Outpost API. + +
+ + + + +
+ + +## Summary + +Outpost API: The Outpost API is a REST-based JSON API for managing tenants, destinations, and publishing events. + + + +## Table of Contents + +* [Outpost Python SDK](#outpost-python-sdk) + * [SDK Installation](#sdk-installation) + * [IDE Support](#ide-support) + * [SDK Example Usage](#sdk-example-usage) + * [Authentication](#authentication) + * [Available Resources and Operations](#available-resources-and-operations) + * [Global Parameters](#global-parameters) + * [Pagination](#pagination) + * [Retries](#retries) + * [Error Handling](#error-handling) + * [Server Selection](#server-selection) + * [Custom HTTP Client](#custom-http-client) + * [Resource Management](#resource-management) + * [Debugging](#debugging) +* [Development](#development) + * [Maturity](#maturity) + * [Contributions](#contributions) + + + + +## SDK Installation + +> [!NOTE] +> **Python version upgrade policy** +> +> Once a Python version reaches its [official end of life date](https://devguide.python.org/versions/), a 3-month grace period is provided for users to upgrade. Following this grace period, the minimum python version supported in the SDK will be updated. + +The SDK can be installed with *uv*, *pip*, or *poetry* package managers. + +### uv + +*uv* is a fast Python package installer and resolver, designed as a drop-in replacement for pip and pip-tools. It's recommended for its speed and modern Python tooling capabilities. + +```bash +uv add outpost_sdk +``` + +### PIP + +*PIP* is the default package installer for Python, enabling easy installation and management of packages from PyPI via the command line. + +```bash +pip install outpost_sdk +``` + +### Poetry + +*Poetry* is a modern tool that simplifies dependency management and package publishing by using a single `pyproject.toml` file to handle project metadata and dependencies. + +```bash +poetry add outpost_sdk +``` + +### Shell and script usage with `uv` + +You can use this SDK in a Python shell with [uv](https://docs.astral.sh/uv/) and the `uvx` command that comes with it like so: + +```shell +uvx --from outpost_sdk python +``` + +It's also possible to write a standalone Python script without needing to set up a whole project like so: + +```python +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "outpost_sdk", +# ] +# /// + +from outpost_sdk import Outpost + +sdk = Outpost( + # SDK arguments +) + +# Rest of script here... +``` + +Once that is saved to a file, you can run it with `uv run script.py` where +`script.py` can be replaced with the actual file name. + + + +## IDE Support + +### PyCharm + +Generally, the SDK will work well with most IDEs out of the box. However, when using PyCharm, you can enjoy much better integration with Pydantic by installing an additional plugin. + +- [PyCharm Pydantic Plugin](https://docs.pydantic.dev/latest/integrations/pycharm/) + + + +## SDK Example Usage + +### Example + +```python +# Synchronous Example +from outpost_sdk import Outpost + + +with Outpost() as outpost: + + res = outpost.health.check() + + # Handle response + print(res) +``` + +
+ +The same SDK client can also be used to make asynchronous requests by importing asyncio. + +```python +# Asynchronous Example +import asyncio +from outpost_sdk import Outpost + +async def main(): + + async with Outpost() as outpost: + + res = await outpost.health.check_async() + + # Handle response + print(res) + +asyncio.run(main()) +``` + + + +## Authentication + +### Per-Client Security Schemes + +This SDK supports the following security schemes globally: + +| Name | Type | Scheme | +| --------------- | ---- | ----------- | +| `admin_api_key` | http | HTTP Bearer | +| `tenant_jwt` | http | HTTP Bearer | + +You can set the security parameters through the `security` optional parameter when initializing the SDK client instance. The selected scheme will be used by default to authenticate with the API for all operations that support it. For example: +```python +from outpost_sdk import Outpost, models + + +with Outpost( + security=models.Security( + admin_api_key="", + ), +) as outpost: + + res = outpost.health.check() + + # Handle response + print(res) + +``` + + + +## Available Resources and Operations + +
+Available methods + +### [Destinations](docs/sdks/destinations/README.md) + +* [list](docs/sdks/destinations/README.md#list) - List Destinations +* [create](docs/sdks/destinations/README.md#create) - Create Destination +* [get](docs/sdks/destinations/README.md#get) - Get Destination +* [update](docs/sdks/destinations/README.md#update) - Update Destination +* [delete](docs/sdks/destinations/README.md#delete) - Delete Destination +* [enable](docs/sdks/destinations/README.md#enable) - Enable Destination +* [disable](docs/sdks/destinations/README.md#disable) - Disable Destination + +### [Events](docs/sdks/events/README.md) + +* [list](docs/sdks/events/README.md#list) - List Events +* [get](docs/sdks/events/README.md#get) - Get Event +* [list_deliveries](docs/sdks/events/README.md#list_deliveries) - List Event Delivery Attempts +* [list_by_destination](docs/sdks/events/README.md#list_by_destination) - List Events by Destination +* [get_by_destination](docs/sdks/events/README.md#get_by_destination) - Get Event by Destination +* [retry](docs/sdks/events/README.md#retry) - Retry Event Delivery + +### [Health](docs/sdks/health/README.md) + +* [check](docs/sdks/health/README.md#check) - Health Check + +### [Publish](docs/sdks/publish/README.md) + +* [event](docs/sdks/publish/README.md#event) - Publish Event + +### [Schemas](docs/sdks/schemas/README.md) + +* [list_tenant_destination_types](docs/sdks/schemas/README.md#list_tenant_destination_types) - List Destination Type Schemas (for Tenant) +* [get](docs/sdks/schemas/README.md#get) - Get Destination Type Schema (for Tenant) +* [list_destination_types_jwt](docs/sdks/schemas/README.md#list_destination_types_jwt) - List Destination Type Schemas (JWT Auth) +* [get_destination_type_jwt](docs/sdks/schemas/README.md#get_destination_type_jwt) - Get Destination Type Schema + +### [Tenants](docs/sdks/tenants/README.md) + +* [list_tenants](docs/sdks/tenants/README.md#list_tenants) - List Tenants +* [upsert](docs/sdks/tenants/README.md#upsert) - Create or Update Tenant +* [get](docs/sdks/tenants/README.md#get) - Get Tenant +* [delete](docs/sdks/tenants/README.md#delete) - Delete Tenant +* [get_portal_url](docs/sdks/tenants/README.md#get_portal_url) - Get Portal Redirect URL +* [get_token](docs/sdks/tenants/README.md#get_token) - Get Tenant JWT Token + +### [Topics](docs/sdks/topicssdk/README.md) + +* [list](docs/sdks/topicssdk/README.md#list) - List Available Topics (for Tenant) +* [list_jwt](docs/sdks/topicssdk/README.md#list_jwt) - List Available Topics) + +
+ + + +## Global Parameters + +A parameter is configured globally. This parameter may be set on the SDK client instance itself during initialization. When configured as an option during SDK initialization, This global value will be used as the default on the operations that use it. When such operations are called, there is a place in each to override the global value, if needed. + +For example, you can set `tenant_id` to `""` at SDK initialization and then you do not have to pass the same value on calls to operations like `upsert`. But if you want to do so you may, which will locally override the global setting. See the example code below for a demonstration. + + +### Available Globals + +The following global parameter is available. + +| Name | Type | Description | +| --------- | ---- | ------------------------ | +| tenant_id | str | The tenant_id parameter. | + +### Example + +```python +from outpost_sdk import Outpost, models + + +with Outpost( + tenant_id="", + security=models.Security( + admin_api_key="", + ), +) as outpost: + + res = outpost.tenants.upsert() + + # Handle response + print(res) + +``` + + + +## Pagination + +Some of the endpoints in this SDK support pagination. To use pagination, you make your SDK calls as usual, but the +returned response object will have a `Next` method that can be called to pull down the next group of results. If the +return value of `Next` is `None`, then there are no more pages to be fetched. + +Here's an example of one such pagination call: +```python +from outpost_sdk import Outpost, models + + +with Outpost( + tenant_id="", + security=models.Security( + admin_api_key="", + ), +) as outpost: + + res = outpost.events.list(limit=100) + + while res is not None: + # Handle items + + res = res.next() + +``` + + + +## Retries + +Some of the endpoints in this SDK support retries. If you use the SDK without any configuration, it will fall back to the default retry strategy provided by the API. However, the default retry strategy can be overridden on a per-operation basis, or across the entire SDK. + +To change the default retry strategy for a single API call, simply provide a `RetryConfig` object to the call: +```python +from outpost_sdk import Outpost +from outpost_sdk.utils import BackoffStrategy, RetryConfig + + +with Outpost() as outpost: + + res = outpost.health.check(, + RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False)) + + # Handle response + print(res) + +``` + +If you'd like to override the default retry strategy for all operations that support retries, you can use the `retry_config` optional parameter when initializing the SDK: +```python +from outpost_sdk import Outpost +from outpost_sdk.utils import BackoffStrategy, RetryConfig + + +with Outpost( + retry_config=RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False), +) as outpost: + + res = outpost.health.check() + + # Handle response + print(res) + +``` + + + +## Error Handling + +[`OutpostError`](./src/outpost_sdk/errors/outposterror.py) is the base class for all HTTP error responses. It has the following properties: + +| Property | Type | Description | +| ------------------ | ---------------- | --------------------------------------------------------------------------------------- | +| `err.message` | `str` | Error message | +| `err.status_code` | `int` | HTTP response status code eg `404` | +| `err.headers` | `httpx.Headers` | HTTP response headers | +| `err.body` | `str` | HTTP body. Can be empty string if no body is returned. | +| `err.raw_response` | `httpx.Response` | Raw HTTP response | +| `err.data` | | Optional. Some errors may contain structured data. [See Error Classes](#error-classes). | + +### Example +```python +from outpost_sdk import Outpost, errors + + +with Outpost() as outpost: + res = None + try: + + res = outpost.health.check() + + # Handle response + print(res) + + + except errors.OutpostError as e: + # The base class for HTTP error responses + print(e.message) + print(e.status_code) + print(e.body) + print(e.headers) + print(e.raw_response) + + # Depending on the method different errors may be thrown + if isinstance(e, errors.NotFoundError): + print(e.data.message) # Optional[str] + print(e.data.additional_properties) # Optional[Dict[str, Any]] +``` + +### Error Classes +**Primary error:** +* [`OutpostError`](./src/outpost_sdk/errors/outposterror.py): The base class for HTTP error responses. + +
Less common errors (13) + +
+ +**Network errors:** +* [`httpx.RequestError`](https://www.python-httpx.org/exceptions/#httpx.RequestError): Base class for request errors. + * [`httpx.ConnectError`](https://www.python-httpx.org/exceptions/#httpx.ConnectError): HTTP client was unable to make a request to a server. + * [`httpx.TimeoutException`](https://www.python-httpx.org/exceptions/#httpx.TimeoutException): HTTP request timed out. + + +**Inherit from [`OutpostError`](./src/outpost_sdk/errors/outposterror.py)**: +* [`BadRequestError`](./src/outpost_sdk/errors/badrequesterror.py): A collection of codes that generally means the end user got something wrong in making the request. Applicable to 5 of 27 methods.* +* [`UnauthorizedError`](./src/outpost_sdk/errors/unauthorizederror.py): A collection of codes that generally means the client was not authenticated correctly for the request they want to make. Applicable to 5 of 27 methods.* +* [`NotFoundError`](./src/outpost_sdk/errors/notfounderror.py): Status codes relating to the resource/entity they are requesting not being found or endpoints/routes not existing. Applicable to 5 of 27 methods.* +* [`TimeoutErrorT`](./src/outpost_sdk/errors/timeouterrort.py): Timeouts occurred with the request. Applicable to 5 of 27 methods.* +* [`RateLimitedError`](./src/outpost_sdk/errors/ratelimitederror.py): Status codes relating to the client being rate limited by the server. Status code `429`. Applicable to 5 of 27 methods.* +* [`InternalServerError`](./src/outpost_sdk/errors/internalservererror.py): A collection of status codes that generally mean the server failed in an unexpected way. Applicable to 5 of 27 methods.* +* [`ListTenantsBadRequestError`](./src/outpost_sdk/errors/listtenantsbadrequesterror.py): Invalid request parameters (e.g., invalid cursor, both next and prev provided). Status code `400`. Applicable to 1 of 27 methods.* +* [`NotImplementedErrorT`](./src/outpost_sdk/errors/notimplementederrort.py): List Tenants feature is not available. Requires Redis with RediSearch module. Status code `501`. Applicable to 1 of 27 methods.* +* [`ResponseValidationError`](./src/outpost_sdk/errors/responsevalidationerror.py): Type mismatch between the response data and the expected Pydantic model. Provides access to the Pydantic validation error via the `cause` attribute. + +
+ +\* Check [the method documentation](#available-resources-and-operations) to see if the error is applicable. + + + +## Server Selection + +### Override Server URL Per-Client + +The default server can be overridden globally by passing a URL to the `server_url: str` optional parameter when initializing the SDK client instance. For example: +```python +from outpost_sdk import Outpost + + +with Outpost( + server_url="http://localhost:3333/api/v1", +) as outpost: + + res = outpost.health.check() + + # Handle response + print(res) + +``` + + + +## Custom HTTP Client + +The Python SDK makes API calls using the [httpx](https://www.python-httpx.org/) HTTP library. In order to provide a convenient way to configure timeouts, cookies, proxies, custom headers, and other low-level configuration, you can initialize the SDK client with your own HTTP client instance. +Depending on whether you are using the sync or async version of the SDK, you can pass an instance of `HttpClient` or `AsyncHttpClient` respectively, which are Protocol's ensuring that the client has the necessary methods to make API calls. +This allows you to wrap the client with your own custom logic, such as adding custom headers, logging, or error handling, or you can just pass an instance of `httpx.Client` or `httpx.AsyncClient` directly. + +For example, you could specify a header for every request that this sdk makes as follows: +```python +from outpost_sdk import Outpost +import httpx + +http_client = httpx.Client(headers={"x-custom-header": "someValue"}) +s = Outpost(client=http_client) +``` + +or you could wrap the client with your own custom logic: +```python +from outpost_sdk import Outpost +from outpost_sdk.httpclient import AsyncHttpClient +import httpx + +class CustomClient(AsyncHttpClient): + client: AsyncHttpClient + + def __init__(self, client: AsyncHttpClient): + self.client = client + + async def send( + self, + request: httpx.Request, + *, + stream: bool = False, + auth: Union[ + httpx._types.AuthTypes, httpx._client.UseClientDefault, None + ] = httpx.USE_CLIENT_DEFAULT, + follow_redirects: Union[ + bool, httpx._client.UseClientDefault + ] = httpx.USE_CLIENT_DEFAULT, + ) -> httpx.Response: + request.headers["Client-Level-Header"] = "added by client" + + return await self.client.send( + request, stream=stream, auth=auth, follow_redirects=follow_redirects + ) + + def build_request( + self, + method: str, + url: httpx._types.URLTypes, + *, + content: Optional[httpx._types.RequestContent] = None, + data: Optional[httpx._types.RequestData] = None, + files: Optional[httpx._types.RequestFiles] = None, + json: Optional[Any] = None, + params: Optional[httpx._types.QueryParamTypes] = None, + headers: Optional[httpx._types.HeaderTypes] = None, + cookies: Optional[httpx._types.CookieTypes] = None, + timeout: Union[ + httpx._types.TimeoutTypes, httpx._client.UseClientDefault + ] = httpx.USE_CLIENT_DEFAULT, + extensions: Optional[httpx._types.RequestExtensions] = None, + ) -> httpx.Request: + return self.client.build_request( + method, + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + timeout=timeout, + extensions=extensions, + ) + +s = Outpost(async_client=CustomClient(httpx.AsyncClient())) +``` + + + +## Resource Management + +The `Outpost` class implements the context manager protocol and registers a finalizer function to close the underlying sync and async HTTPX clients it uses under the hood. This will close HTTP connections, release memory and free up other resources held by the SDK. In short-lived Python programs and notebooks that make a few SDK method calls, resource management may not be a concern. However, in longer-lived programs, it is beneficial to create a single SDK instance via a [context manager][context-manager] and reuse it across the application. + +[context-manager]: https://docs.python.org/3/reference/datamodel.html#context-managers + +```python +from outpost_sdk import Outpost +def main(): + + with Outpost() as outpost: + # Rest of application here... + + +# Or when using async: +async def amain(): + + async with Outpost() as outpost: + # Rest of application here... +``` + + + +## Debugging + +You can setup your SDK to emit debug logs for SDK requests and responses. + +You can pass your own logger class directly into your SDK. +```python +from outpost_sdk import Outpost +import logging + +logging.basicConfig(level=logging.DEBUG) +s = Outpost(debug_logger=logging.getLogger("outpost_sdk")) +``` + + + + +# Development + +## Maturity + +This SDK is in beta, and there may be breaking changes between versions without a major version update. Therefore, we recommend pinning usage +to a specific package version. This way, you can install the same version each time without breaking changes unless you are intentionally +looking for the latest version. + +## Contributions + +While we value open-source contributions to this SDK, this library is generated programmatically. Any manual changes added to internal files will be overwritten on the next generation. +We look forward to hearing your feedback. Feel free to open a PR or an issue with a proof of concept and we'll do our best to include it in a future release. + +### SDK Created by [Speakeasy](https://www.speakeasy.com/?utm_source=openapi&utm_campaign=python) diff --git a/sdks/outpost-python/pyproject.toml b/sdks/outpost-python/pyproject.toml index e269b6aea..255213f6b 100644 --- a/sdks/outpost-python/pyproject.toml +++ b/sdks/outpost-python/pyproject.toml @@ -4,7 +4,7 @@ name = "outpost_sdk" version = "0.5.0" description = "Python Client SDK Generated by Speakeasy." authors = [{ name = "Speakeasy" },] -readme = "README.md" +readme = "README-PYPI.md" requires-python = ">=3.9.2" dependencies = [ "httpcore >=1.0.9", diff --git a/sdks/outpost-python/scripts/patch_pyproject_readme.py b/sdks/outpost-python/scripts/patch_pyproject_readme.py deleted file mode 100644 index 96de3eb16..000000000 --- a/sdks/outpost-python/scripts/patch_pyproject_readme.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Override Speakeasy-generated pyproject.toml to use README.md as the package readme. - -Speakeasy emits readme = "README-PYPI.md" but does not generate that file. We use -README.md as the single source of truth for the SDK; this script patches pyproject.toml -after generation so build/test work. At publish time, prepare_readme.py creates -README-PYPI.md and publish.sh builds with it. -""" -import sys - -PYPROJECT = "pyproject.toml" -OLD = 'readme = "README-PYPI.md"' -NEW = 'readme = "README.md"' - - -def main() -> int: - try: - with open(PYPROJECT, "r", encoding="utf-8") as f: - content = f.read() - except OSError as e: - print(f"Failed to read {PYPROJECT}: {e}", file=sys.stderr) - return 1 - - if OLD not in content: - if NEW in content: - return 0 # Already patched - print(f"Neither {OLD!r} nor {NEW!r} found in {PYPROJECT}", file=sys.stderr) - return 1 - - content = content.replace(OLD, NEW, 1) - try: - with open(PYPROJECT, "w", encoding="utf-8") as f: - f.write(content) - except OSError as e: - print(f"Failed to write {PYPROJECT}: {e}", file=sys.stderr) - return 1 - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/sdks/outpost-python/scripts/publish.sh b/sdks/outpost-python/scripts/publish.sh index be22fa79f..7861eb0e2 100755 --- a/sdks/outpost-python/scripts/publish.sh +++ b/sdks/outpost-python/scripts/publish.sh @@ -1,10 +1,7 @@ #!/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. +# pyproject.toml points at README-PYPI.md (Speakeasy default). prepare_readme.py +# overwrites it with link-rewritten content from README.md for PyPI. export POETRY_PYPI_TOKEN_PYPI=${PYPI_TOKEN} 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