Skip to content

SDK regeneration#50

Closed
chiragjn wants to merge 1 commit intomainfrom
cj-upgrade-python-gen
Closed

SDK regeneration#50
chiragjn wants to merge 1 commit intomainfrom
cj-upgrade-python-gen

Conversation

@chiragjn
Copy link
Copy Markdown
Member

@chiragjn chiragjn commented Apr 16, 2026

Note

Low Risk
Changes are limited to SDK generation metadata, docs, and dependency/lockfile updates with no direct runtime logic modifications in the source tree.

Overview
Updates Fern Python SDK generator metadata (generatorVersion to 5.5.0) and adjusts generation config to apply request defaults.

Refreshes the README examples (token placeholder, import formatting, and pagination snippets) to match the current applications.list usage.

Updates packaging: adds optional aiohttp/httpx-aiohttp extra (with pytest marker) and constrains pydantic-core with an upper bound; regenerates poetry.lock accordingly.

Reviewed by Cursor Bugbot for commit a19685a. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added optional aiohttp support for improved async HTTP client performance with automatic fallback.
    • Introduced SDK-wide logging configuration for debugging and monitoring.
    • Added RFC 2822 datetime parsing support.
  • Improvements

    • Enhanced error handling with detailed parsing error messages for API responses.
    • Improved URL path parameter encoding across API endpoints.
    • Updated README examples with current API usage patterns.
  • Dependencies

    • Added optional aiohttp and httpx-aiohttp packages.
    • Updated pydantic-core version constraints.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 16, 2026

Walkthrough

This PR modernizes the TrueFoundry SDK by introducing comprehensive logging infrastructure, systematic response validation error handling via ParsingError, automatic aiohttp-based async HTTP client support with fallback options, RFC 2822 datetime parsing capabilities, and upgrading the Python SDK generator from version 4.54.3 to 5.5.0. Path parameter encoding is standardized across all API endpoints using encode_path_param, and HTTP client retry logic is enhanced with detailed logging and exponential backoff.

Changes

Cohort / File(s) Summary
Core Logging Infrastructure
src/truefoundry_sdk/core/logging.py, src/truefoundry_sdk/core/__init__.py
New logging module with LogLevel, ILogger protocol, ConsoleLogger, LogConfig typed dict, Logger class, and create_logger() factory. Exports added to core module and _dynamic_imports routing.
Error Handling & Parsing
src/truefoundry_sdk/core/parse_error.py, src/truefoundry_sdk/core/__init__.py, src/truefoundry_sdk/core/client_wrapper.py
New ParsingError exception class for response validation failures. Added logging parameter to BaseClientWrapper, SyncClientWrapper, and AsyncClientWrapper constructors for logging config propagation.
HTTP Client & DateTime Support
src/truefoundry_sdk/core/http_client.py, src/truefoundry_sdk/core/datetime_utils.py, src/truefoundry_sdk/core/jsonable_encoder.py
Enhanced HTTP client with logging, retry backoff (_retry_timeout_from_retries), header redaction, and connection error retry logic. Added RFC 2822 datetime parsing (parse_rfc2822_datetime, Rfc2822DateTime). New encode_path_param() utility for URL path parameter encoding.
Default HTTP Clients
src/truefoundry_sdk/_default_clients.py, src/truefoundry_sdk/__init__.py, src/truefoundry_sdk/base_client.py
New module with DefaultAsyncHttpxClient and DefaultAioHttpClient (conditional on httpx_aiohttp availability). BaseTrueFoundry and AsyncBaseTrueFoundry now support logging parameter and async token acquisition; added _make_default_async_client() helper for client auto-detection.
Pydantic & Utilities
src/truefoundry_sdk/core/pydantic_utilities.py, src/truefoundry_sdk/core/custom_pagination.py
Updated Pydantic v2 compat layer to use TypeAdapter for date/datetime parsing and inline encoders_by_type mapping. Removed SyncCustomPager and AsyncCustomPager classes (deprecated).
SDK Metadata & Dependencies
.fern/metadata.json, pyproject.toml, requirements.txt
Generator version upgraded to 5.5.0. Added optional dependencies: aiohttp >=3.10.0,<4 and httpx-aiohttp 0.1.8. Updated pydantic-core constraint to >=2.18.2,<2.44.0. Added pytest aiohttp marker and Poetry extra.
README & Documentation
README.md, src/truefoundry_sdk/types/non_negative_float.py
Simplified code examples: removed generator-based iteration, updated API key placeholder, reformatted imports. Added UI props comment to NonNegativeFloat type.
Raw Client Path Encoding & Validation
src/truefoundry_sdk/.../raw_client.py (40+ files)
Systematic updates across all endpoint raw clients: replaced jsonable_encoder(id) with encode_path_param(id) for URL path parameters; added except ValidationError handlers that raise ParsingError with context (status code, headers, body, cause) after JSONDecodeError handling. Files affected include applications, agents, artifacts, clusters, deployments, environments, events, jobs, logs, models, ml\_repos, personal\_access\_tokens, prompts, secrets, teams, users, virtual\_accounts, workspaces, and many internal API clients.
Tests
tests/conftest.py, tests/test_aiohttp_autodetect.py, tests/utils/test_http_client.py
Added pytest conftest with conditional aiohttp marker skipping. New test suite for aiohttp client autodetection (presence/absence of httpx_aiohttp), default client behavior, and timeout/redirect handling. Extended HTTP client tests with retry logic coverage: connection errors, retry budgets, sleep delays, and max_retries option propagation.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AsyncBaseTrueFoundry
    participant _make_default_async_client
    participant httpx_aiohttp
    participant httpx
    
    Client->>AsyncBaseTrueFoundry: __init__(logging=..., async_token=...)
    AsyncBaseTrueFoundry->>_make_default_async_client: (when no httpx_client provided)
    alt httpx_aiohttp available
        _make_default_async_client->>httpx_aiohttp: HttpxAiohttpClient(timeout, follow_redirects)
        httpx_aiohttp-->>_make_default_async_client: client instance
    else httpx_aiohttp unavailable
        _make_default_async_client->>httpx: AsyncClient(timeout, follow_redirects)
        httpx-->>_make_default_async_client: client instance
    end
    _make_default_async_client-->>AsyncBaseTrueFoundry: async_http_client
    AsyncBaseTrueFoundry->>AsyncClientWrapper: __init__(logging, async_token, httpx_client)
    AsyncClientWrapper-->>Client: ready for requests
Loading
sequenceDiagram
    participant HTTPClient
    participant Request
    participant Logger
    participant httpx
    participant Retry Logic
    
    HTTPClient->>Logger: debug("Outbound request", headers=redacted)
    HTTPClient->>httpx: request()
    alt Success (2xx/3xx)
        httpx-->>HTTPClient: Response
        HTTPClient->>Logger: info("Response", status=code)
        HTTPClient-->>Request: parsed_response
    else ConnectError or RemoteProtocolError
        httpx-->>HTTPClient: exception
        HTTPClient->>Retry Logic: retries < max_retries?
        alt Retries remaining
            Retry Logic->>Retry Logic: sleep(exponential_backoff)
            Retry Logic->>httpx: request() [recursive]
        else No retries left
            Retry Logic-->>HTTPClient: re-raise exception
        end
    else Status >= 400
        httpx-->>HTTPClient: Response
        HTTPClient->>Logger: error("Response", status=code)
        alt ValidationError during parse
            HTTPClient-->>Request: ParsingError(status, headers, body, cause)
        else JSONDecodeError
            HTTPClient-->>Request: ApiError
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 The SDK hops forward with logging so bright,
Path encoding and errors now handled just right!
Aiohttp clients auto-detect with such grace,
While retries backoff at a measured pace—
A hoppy refactor to set the new pace! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'SDK regeneration' is vague and generic, using a non-descriptive term that doesn't convey meaningful information about the specific changeset. Use a more specific title that describes the key changes, such as 'Add async HTTP client support and improve error handling' or 'Upgrade Python SDK generator and add aiohttp client integration'.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 81.48% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cj-upgrade-python-gen

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/truefoundry_sdk/application_versions/raw_client.py`:
- Line 68: The public raw client is percent-encoding path parameters (using
encode_path_param) when constructing URLs like
"api/svc/v1/apps/{encode_path_param(id)}/deployments" which will double-encode
inputs already escaped by callers; remove the encode_path_param calls from the
public client URL construction so IDs and deployment_id are used verbatim (e.g.,
change occurrences of encode_path_param(id) and encode_path_param(deployment_id)
in src/truefoundry_sdk/application_versions/raw_client.py to the raw parameter)
or alternatively add a clear migration note if you intend this breaking
change—update the URL-building sites referenced (the lines using
encode_path_param in the deployments and app-specific endpoint builders)
accordingly.

In `@src/truefoundry_sdk/data_directories/raw_client.py`:
- Around line 83-86: The change wraps pydantic.ValidationError into a custom
ParsingError (via the except block that catches ValidationError and raises
ParsingError), which breaks the public exception contract; revert this by
preserving the original ValidationError surface: in the except ValidationError
handlers around parse_obj_as(...) in raw_client.py (the blocks that currently
raise ParsingError) stop converting to ParsingError and re-raise the caught
ValidationError (or raise a new ValidationError enriched with response metadata)
so callers still receive pydantic.ValidationError; apply the same fix to the
other matching handlers mentioned (the block around lines 658-661).

In `@src/truefoundry_sdk/prompts/raw_client.py`:
- Around line 79-82: The diff changes public methods to convert a caught
ValidationError into a ParsingError, breaking callers that catch
ValidationError; revert this by preserving the original ValidationError for the
public raw client methods (replace the current except ValidationError: raise
ParsingError(...) behavior), i.e. when parsing fails in the sync/async blocks
referenced (symbols: ValidationError, ParsingError, _response, cause) re-raise
the original ValidationError (or raise a new ValidationError that includes
response context via chaining) so existing except ValidationError handlers
continue to work; apply this fix to all the corresponding blocks mentioned
(around the ValidationError handlers at the listed locations).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 409e1db3-284b-4cf2-bcd7-4063001edfdc

📥 Commits

Reviewing files that changed from the base of the PR and between 8ded527 and a19685a.

⛔ Files ignored due to path filters (1)
  • poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (61)
  • .fern/metadata.json
  • README.md
  • pyproject.toml
  • reference.md
  • requirements.txt
  • src/truefoundry_sdk/__init__.py
  • src/truefoundry_sdk/_default_clients.py
  • src/truefoundry_sdk/agent_skill_versions/raw_client.py
  • src/truefoundry_sdk/agent_skills/raw_client.py
  • src/truefoundry_sdk/alerts/raw_client.py
  • src/truefoundry_sdk/application_versions/raw_client.py
  • src/truefoundry_sdk/applications/raw_client.py
  • src/truefoundry_sdk/artifact_versions/raw_client.py
  • src/truefoundry_sdk/artifacts/raw_client.py
  • src/truefoundry_sdk/base_client.py
  • src/truefoundry_sdk/clusters/raw_client.py
  • src/truefoundry_sdk/core/__init__.py
  • src/truefoundry_sdk/core/client_wrapper.py
  • src/truefoundry_sdk/core/custom_pagination.py
  • src/truefoundry_sdk/core/datetime_utils.py
  • src/truefoundry_sdk/core/http_client.py
  • src/truefoundry_sdk/core/jsonable_encoder.py
  • src/truefoundry_sdk/core/logging.py
  • src/truefoundry_sdk/core/parse_error.py
  • src/truefoundry_sdk/core/pydantic_utilities.py
  • src/truefoundry_sdk/data_directories/raw_client.py
  • src/truefoundry_sdk/environments/raw_client.py
  • src/truefoundry_sdk/events/raw_client.py
  • src/truefoundry_sdk/internal/ai_gateway/raw_client.py
  • src/truefoundry_sdk/internal/applications/raw_client.py
  • src/truefoundry_sdk/internal/artifact_versions/raw_client.py
  • src/truefoundry_sdk/internal/build_logs/raw_client.py
  • src/truefoundry_sdk/internal/clusters/raw_client.py
  • src/truefoundry_sdk/internal/deployments/raw_client.py
  • src/truefoundry_sdk/internal/docker_registries/raw_client.py
  • src/truefoundry_sdk/internal/metrics/raw_client.py
  • src/truefoundry_sdk/internal/ml/raw_client.py
  • src/truefoundry_sdk/internal/raw_client.py
  • src/truefoundry_sdk/internal/users/raw_client.py
  • src/truefoundry_sdk/internal/vcs/raw_client.py
  • src/truefoundry_sdk/internal/workflows/raw_client.py
  • src/truefoundry_sdk/jobs/raw_client.py
  • src/truefoundry_sdk/logs/raw_client.py
  • src/truefoundry_sdk/ml_repos/raw_client.py
  • src/truefoundry_sdk/model_versions/raw_client.py
  • src/truefoundry_sdk/models/raw_client.py
  • src/truefoundry_sdk/personal_access_tokens/raw_client.py
  • src/truefoundry_sdk/prompt_versions/raw_client.py
  • src/truefoundry_sdk/prompts/raw_client.py
  • src/truefoundry_sdk/raw_base_client.py
  • src/truefoundry_sdk/secret_groups/raw_client.py
  • src/truefoundry_sdk/secrets/raw_client.py
  • src/truefoundry_sdk/teams/raw_client.py
  • src/truefoundry_sdk/traces/raw_client.py
  • src/truefoundry_sdk/types/non_negative_float.py
  • src/truefoundry_sdk/users/raw_client.py
  • src/truefoundry_sdk/virtual_accounts/raw_client.py
  • src/truefoundry_sdk/workspaces/raw_client.py
  • tests/conftest.py
  • tests/test_aiohttp_autodetect.py
  • tests/utils/test_http_client.py
💤 Files with no reviewable changes (1)
  • src/truefoundry_sdk/core/custom_pagination.py


_response = self._client_wrapper.httpx_client.request(
f"api/svc/v1/apps/{jsonable_encoder(id)}/deployments",
f"api/svc/v1/apps/{encode_path_param(id)}/deployments",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Percent-encoding path params changes what public callers can pass here.

These public methods now encode id and deployment_id before building the URL. Callers that already pass escaped identifiers into the SDK will now get double-encoding (%2F%252F), so this needs a migration note or another compatibility plan if this release is meant to stay non-breaking.

Based on learnings, for autogenerated SDK regeneration PRs in truefoundry/truefoundry-python-sdk, chiragjn wants only interface-breaking issues called out on the public client.v1 surface.

Also applies to: 152-152, 243-243, 330-330

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/truefoundry_sdk/application_versions/raw_client.py` at line 68, The
public raw client is percent-encoding path parameters (using encode_path_param)
when constructing URLs like
"api/svc/v1/apps/{encode_path_param(id)}/deployments" which will double-encode
inputs already escaped by callers; remove the encode_path_param calls from the
public client URL construction so IDs and deployment_id are used verbatim (e.g.,
change occurrences of encode_path_param(id) and encode_path_param(deployment_id)
in src/truefoundry_sdk/application_versions/raw_client.py to the raw parameter)
or alternatively add a clear migration note if you intend this breaking
change—update the URL-building sites referenced (the lines using
encode_path_param in the deployments and app-specific endpoint builders)
accordingly.

Comment on lines +83 to +86
except ValidationError as e:
raise ParsingError(
status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Wrapping response-schema mismatches in ParsingError is a breaking exception-contract change.

Before this regen, parse_obj_as(...) validation failures from these public raw-client methods bubbled out as pydantic.ValidationError; now they raise ParsingError instead. That breaks callers that currently catch ValidationError for response drift, so this either needs to preserve the old exception surface or be treated/documented as an explicit breaking change.

Based on learnings, for autogenerated SDK regeneration PRs in truefoundry/truefoundry-python-sdk, chiragjn wants only interface-breaking issues called out on the public client.v1 surface.

Also applies to: 658-661

🧰 Tools
🪛 Ruff (0.15.10)

[warning] 84-86: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/truefoundry_sdk/data_directories/raw_client.py` around lines 83 - 86, The
change wraps pydantic.ValidationError into a custom ParsingError (via the except
block that catches ValidationError and raises ParsingError), which breaks the
public exception contract; revert this by preserving the original
ValidationError surface: in the except ValidationError handlers around
parse_obj_as(...) in raw_client.py (the blocks that currently raise
ParsingError) stop converting to ParsingError and re-raise the caught
ValidationError (or raise a new ValidationError enriched with response metadata)
so callers still receive pydantic.ValidationError; apply the same fix to the
other matching handlers mentioned (the block around lines 658-661).

Comment on lines +79 to +82
except ValidationError as e:
raise ParsingError(
status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Breaking exception contract in public prompts raw client methods

Line 79 (and corresponding async/sync blocks) changes response-validation failures from surfacing ValidationError to surfacing ParsingError. That is a caller-visible behavior change and can break existing except ValidationError handling paths.

Please either preserve prior exception behavior for these public methods or explicitly treat this as a breaking SDK change (versioning + release notes/migration note).

Based on learnings: For autogenerated SDK regeneration PRs in truefoundry/truefoundry-python-sdk, only interface-breaking issues should be called out (public client.v1 surface, removed/renamed types/enums/fields, and behavior that breaks callers).

Also applies to: 133-135, 231-233, 294-296, 352-354, 405-407, 506-508, 569-571

🧰 Tools
🪛 Ruff (0.15.10)

[warning] 80-82: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/truefoundry_sdk/prompts/raw_client.py` around lines 79 - 82, The diff
changes public methods to convert a caught ValidationError into a ParsingError,
breaking callers that catch ValidationError; revert this by preserving the
original ValidationError for the public raw client methods (replace the current
except ValidationError: raise ParsingError(...) behavior), i.e. when parsing
fails in the sync/async blocks referenced (symbols: ValidationError,
ParsingError, _response, cause) re-raise the original ValidationError (or raise
a new ValidationError that includes response context via chaining) so existing
except ValidationError handlers continue to work; apply this fix to all the
corresponding blocks mentioned (around the ValidationError handlers at the
listed locations).

Comment on lines +117 to +120
except ValidationError as e:
raise ParsingError(
status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== parse_error.py ==="
fd '^parse_error\.py$' src/truefoundry_sdk/core -x sed -n '1,160p' {}

echo
echo "=== api_error.py ==="
fd '^api_error\.py$' src/truefoundry_sdk/core -x sed -n '1,160p' {}

echo
echo "=== validation-remap sites ==="
rg -n -C2 'except ValidationError as e|raise ParsingError' src/truefoundry_sdk

Repository: truefoundry/truefoundry-python-sdk

Length of output: 50391


This exception-contract change breaks existing error handlers.

The regeneration remaps pydantic.ValidationError to ParsingError across all public client methods. Since ParsingError does not inherit from ApiError or from pydantic.ValidationError, existing callers with except ValidationError or except ApiError handlers will no longer catch response-schema failures. Either make ParsingError inherit from the appropriate base exception or document this as an explicit breaking change.

🧰 Tools
🪛 Ruff (0.15.10)

[warning] 118-120: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 16, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@chiragjn chiragjn closed this Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant