Skip to content

SDK 1.17.0 regeneration + pydantic extraction schemas - #78

Merged
jordanalexmeyer merged 7 commits into
masterfrom
fern-bot/2026-07-29_21-02-26_813
Jul 29, 2026
Merged

SDK 1.17.0 regeneration + pydantic extraction schemas#78
jordanalexmeyer merged 7 commits into
masterfrom
fern-bot/2026-07-29_21-02-26_813

Conversation

@fern-api

@fern-api fern-api Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Combines two changes on top of a fresh Fern regeneration from documentation main:

  1. SDK regeneration to 1.17.0 — generated from current docs OpenAPI (includes workflow run package / multifile support, evaluation-set metric types, Created by fields, etc.). Fern-replay conflicts on pyproject.toml and client_wrapper.py resolved (kept generated 1.17.0 version strings).
  2. Pydantic extraction schema support — previously #77; stacked on top of the regen. Pass a pydantic.BaseModel as config["schema"] for typed extraction end-to-end.

Supersedes closed #76 (stale vs docs main) and #77 (pydantic-only, pre-regen).

from typing import Optional
from pydantic import BaseModel, Field
from extend_ai import Extend, ExtendCurrency, ExtendDate

class Invoice(BaseModel):
    invoice_number: Optional[str] = Field(None, description="The invoice number")
    invoice_date: ExtendDate = Field(None, description="The invoice date")
    total: Optional[ExtendCurrency] = None

client = Extend(token="...")
result = client.extract(
    file={"url": "https://example.com/invoice.pdf"},
    config={"schema": Invoice},
)
if result.status == "PROCESSED" and result.output is not None:
    print(result.output.value.invoice_number)

Notable regen follow-ups

  • workflow_runs.create_and_poll() now accepts/forwards the new package param (caught by signature-parity tests).
  • typing_extensions floor bumped to >= 4.3.0 (required for generic TypedDicts used by typed configs).

Pydantic feature highlights

  • Fail-fast: non-Optional primitives/enums/dates, recursive models, field aliases, and List[Optional[T]] raise SchemaConversionError before any request
  • ExtractOutputValidationError preserves the completed run if residual validation fails
  • Typed schemas on extract(), extract_runs.create() / create_and_poll(), extractors.create()/update(), extractor_versions.create()
  • Signature-parity tests guard wrapper drift from future Fern gens

Test plan

  • Local pytest tests/wrapper tests/custom (259 passed, 1 pre-existing skip)
  • Local mypy . clean
  • CI compile + test green on this PR

fern-api Bot and others added 7 commits July 29, 2026 21:02
Generated by Fern
CLI Version: unknown
Generators:
  - fernapi/fern-python-sdk: 4.53.0
Patches with unresolved conflicts (2):
  - patch-29b579f8: patch
  - patch-4df4e73b: bump
    Run `fern-replay resolve` to apply these customizations.
Patches replayed:
  - patch-29b579f8: patch
  - patch-4df4e73b: bump
Pass a pydantic BaseModel subclass as config["schema"] (or
extractor["override_config"]["schema"]) and the SDK converts it to
Extend's JSON Schema subset for the request, then validates the
extraction output back into model instances (TypedExtractRun).

Mirrors the TypeScript SDK's Zod support across the same four
integration points: extract(), extract_runs.create_and_poll(),
extractors.create()/update(), and extractor_versions.create().

- New wrapper/schema module: ExtendDate/ExtendCurrency/ExtendSignature
  field types, pydantic_to_extend_schema conversion with
  SchemaConversionError, typed run wrappers, config detection helpers
- Works with pydantic v1 and v2
- Overload signatures give full static inference:
  result.output.value is typed as the schema model
The wrapper layer re-declares parts of the generated API surface, which
can silently go stale when Fern regenerates the SDK with new parameters.
True overrides (extract(), extractors.create()/update(), etc.) are
already protected because mypy rejects overrides incompatible with the
generated superclass, but create_and_poll(), the typed config
TypedDicts, and TypedExtractRun had no guard.

These tests fail CI whenever a generated create() gains a parameter
that create_and_poll() doesn't forward, a config key is missing from
the typed TypedDicts, or ExtractRun gains a field TypedExtractRun
doesn't mirror.

Also fixes drift the new tests caught: parse_runs.create_and_poll()
was missing the metadata and data_retention parameters that the
generated parse_runs.create() accepts.
Stop silently force-nullabling primitives in the converter — that was
defeating the API's 2026-02-09 strict schema validation and could defer
user mistakes until after a paid run completed. Non-Optional primitives,
enums, and dates now raise SchemaConversionError before any request is
sent. Also:

- Detect recursive models and raise SchemaConversionError instead of a
  fatal stack overflow
- Recognize typing.Literal on Python 3.8 (distinct from typing_extensions)
- Reject field aliases (they caused silent None validation) and
  Optional array items
- Wrap residual output validation failures in ExtractOutputValidationError
  that preserves the completed ExtractRun (id, dashboard URL, raw output)
- Convert pydantic schemas in plain extract_runs.create() so users don't
  hit a cryptic encoder error
- Bump typing_extensions floor to >=4.3.0 for generic TypedDict support
The 1.17.0 regeneration added package (multifile) support to
workflow_runs.create(); create_and_poll now accepts and forwards it,
matching the file/package mutual-exclusivity pattern used elsewhere.
@jordanalexmeyer jordanalexmeyer changed the title SDK regeneration SDK 1.17.0 regeneration + pydantic extraction schemas Jul 29, 2026
@jordanalexmeyer
jordanalexmeyer merged commit 10e54c2 into master Jul 29, 2026
4 checks passed
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