5.12.3

(chore): Bump the python-sdk container’s Node.js stage from node:20.19.4-slim (Node 20 went EOL March 24, 2026) to node:22.22-bookworm-slim, and apply latest Debian trixie security updates at build time so OS-level package CVEs are picked up. Addresses CVE-2025-55130 (Node 20.19.4 permission-model symlink bypass) and the OS-level CVE-2026-31789 against openssl 3.5.1-1.


5.12.2

(chore): Apply latest Debian security updates to the python pydantic generator container (python:3.11.13) at build time so OS-level package CVEs are picked up.


5.12.1

(fix): Apply canonical “all user-specified examples, else first autogenerated” selection in the Python v2 SDK snippet output path. Aligns the v2 generator’s snippet.json / README example selection with the existing v1 behavior so dynamic-IR-driven snippets are deterministic across runs.

5.12.0

(feat): Add a client-level max_retries: Optional[int] constructor parameter to generated SDK clients. Consumers can now set a default retry count once at client construction (e.g. Client(max_retries=5)) instead of passing max_retries via request_options on every call. Per-request max_retries in request_options continues to take precedence over the client-level default.

5.11.0

(feat): New flatten_union_request_bodies config flag (default false). When enabled, endpoints whose referenced request body is a discriminated oneOf/union expose all variants’ fields as flat kwargs (Stripe-style), rather than a single request: Union[...] parameter. The discriminator becomes a Union[Literal[...], ...] of every variant value; per-variant fields with the same wire name are merged (with conflicting types unioned). Existing customers see no change unless they opt in.


5.10.0

(feat): Generate CONTRIBUTING.md for Python SDKs.

5.9.2

(fix): Widen the generated pydantic-core constraint from >=2.18.2,<2.44.0 to >=2.18.2,<3.0.0, unblocking customers who need newer pydantic-core (e.g. 2.46.x, required by pydantic 2.13). The previous cap targeted 2.44.0’s missing wheels; that release is yanked on PyPI, so the explicit cap is no longer needed.


5.9.1

(fix): Respect the customer’s smart-casing flag from generators.yml when computing Python identifiers from compressed v66 IR strings. Previously the v1 Python generator’s _smart_snake and v2’s PYTHON_CASE_CONVERTER were both hardcoded with smartCasing: true, causing names produced by the generator to diverge from the IR’s pre-computed snake_case values when the customer set smart-casing: false. This manifested as wire-test method calls and Pydantic field aliases that did not exist on the generated client (e.g. test calling set_fcmv_1_provider() while the client method was named set_fcmv1provider).

_smart_snake and the v2 caseConverter now read casingsConfig.smartCasing from the IR and switch between smart-casing semantics (default) and plain lodash semantics (smart-casing: false). No effect for customers who use the default; fixes generation for customers like auth0 that opt out.


5.9.0

(feat): Add retryStatusCodes config with "legacy" and "recommended" modes. Legacy (default) preserves current behavior (408, 409, 429, >= 500). Recommended retries only transient codes (408, 409, 429, 502, 503, 504), avoiding idempotency issues with 500. A 6.0.0 migration auto-pins legacy for upgrading users.

5.8.4

(chore): Bump @fern-api/generator-cli to 0.9.21, which includes @fern-api/replay 0.14.0 with fixes for silent customization loss across apply and resolve paths, per-patch-region diff, and clean follow-up patch preservation.


5.8.3

(fix): Fix async SSE parsing to only split on SSE-spec line terminators (\n, \r, \r\n). Previously, aiter_sse() used httpx’s aiter_lines() which splits on \u2028 and \u2029 via Python’s str.splitlines(), corrupting data fields containing those characters (common in LLM JSON output).

5.8.2

(chore): Bump @fern-api/generator-cli to 0.9.16, which bundles the autoversion pipeline’s private workspace deps (@fern-api/logging-execa, @fern-api/task-context, @fern-api/cli-ai) into the published dist/api.js so consumers no longer hit ERR_MODULE_NOT_FOUND on logging-execa/src/createLoggingExecutable.js under Vite/Vitest.


5.8.1

(chore): Tighten the generated urllib3 dev-dependency pin to >=2.6.3,<3.0.0 (Python >= 3.9) to address CVE-2026-21441 and several additional HIGH-severity urllib3 advisories. Projects still supporting Python 3.8 fall back to the tightest safe constraint available for the 1.x line.

5.8.0

(feat): Support omitting username or password from basic auth when configured via usernameOmit or passwordOmit in the IR. Omitted fields are removed from the SDK’s public API and treated as empty strings internally (e.g., omitting password encodes username:, omitting username encodes :password). When both are omitted, the Authorization header is skipped entirely.


5.7.0

(feat): Use auth scheme placeholder values in README snippets when configured via placeholder field on auth schemes.


5.6.1

(fix): Fix @fern-api/python-dynamic-snippets to respect the use_typeddict_requests configuration option. When enabled, dynamic snippets now generate dict literals instead of Pydantic model constructors for object and discriminated union types.

5.6.0

(feat): Support x-fern-default as fallback value for parameters in generated Python SDKs. When a header, query parameter, or path parameter has a clientDefault value in the IR, the generated Python function signature makes that parameter optional with the default value automatically applied. This enables patterns like optional API version headers that fall back to a pinned version.