GeezerVison is showing github.com — fix: stop failing on rejected jobs and add skip_preflight (0.47.0) by CyMule · Pull Request #356 · Unstructured-IO/unstructured-python-client
Conversation
CyMule
commented
Oct 16, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
What
Jobs the new preflight check rejects no longer break the SDK. Workflows can also opt out of preflight from the SDK.
Before, after a job is rejected:
client.jobs.list_jobs(...) → ValidationError: 'REJECTED' is not a valid JobStatus (whole page lost)
client.jobs.get_job(...) → ValidationError
After:
job.status → JobStatus.REJECTED
job.status → "SOME_FUTURE_STATUS" # a status this SDK version doesn't know comes back as a plain str instead of raising
details.node_stats[0].failure_category → PreflightFailureCategory.AUTH_INVALID_CREDENTIAL
details.node_stats[0].failure_reason → "The AWS Access Key Id you provided does not exist."
JobStatus and JobProcessingStatus gain REJECTED. JobInformation.status and JobDetails.processing_status also accept unknown values. Known values are still enum members, so job.status == JobStatus.COMPLETED and .value behave as before.
JobNodeDetails gains failure_category (Union[PreflightFailureCategory, str]) and failure_reason, so a caller can see why a job was rejected. The server sets them only on the node that failed preflight; before this, pydantic dropped them.
skip_preflight is now on CreateWorkflow, UpdateWorkflow (unset = unchanged) and WorkflowInformation. For a one-off create_job, the API defines the flag inside the request_data JSON. The docs now say to set it there; the SDK does not rewrite that string.
- Releases as 0.47.0.
Why
The SDK models used to be regenerated from the API spec every night. That generator has been dead since January (removed in #349). Since then, new server values reach the SDK only when someone adds them by hand. REJECTED didn't get added, and a closed enum turns a new value into a hard failure.
This PR also adds a way to catch that kind of drift before a customer does (DTPL-696 acceptance criterion 4):
weekly CI → fetch live OpenAPI specs → compare with SDK models → new missing field/enum value → open/update a GitHub issue
(a failed download fails the run but opens no issue)
make check-spec-drift runs the check locally. Gaps we already know about are recorded in scripts/spec_drift_baseline.json (20 schemas today, e.g. JobInformation.processing_status, the teradata connector type). The check fails only on new drift, or on a baseline entry that has since been covered.
CONTRIBUTING.md documents how to resolve a drift issue.
Replaces #353, which got here through a custom _missing_ enum hook and code that spliced bytes into request_data. This version uses a plain pydantic union and leaves request_data alone.
Notes for consumers
- Type checkers now see these two status fields as
Union[JobStatus, str] / Union[JobProcessingStatus, str]. Code that reads .value or .name on them needs to handle the str case. Runtime behavior for known statuses is unchanged.
- Follow-up, not in this PR: the SDK's other "open" enums (connector types, partition
Strategy, etc.) use OpenEnumMeta / validate_open_enum. On Python 3.12+ those return a raw str even for known values, and they emit pydantic serializer warnings. The long-term fix is to move them to the same union pattern used here. That changes their runtime types, so it belongs in its own PR.
Validation
make test-unit: 419 passed. make test-contract: 72 passed. The new job/workflow contract tests pass on Python 3.11, 3.12 and 3.13, and they fail without the model changes.
make lint is clean. make check-spec-drift passes against the live specs.
- Two rounds of Codex review. Round 1 found that enums declared inline on a property escaped the drift check; that is fixed and has a test. Round 2 was clean.
- cubic: three findings fixed (no drift issue on a fetch failure, no duplicate issues from overlapping runs, changelog wording). Re-review clean, and full CI is green, including integration on 3.11–3.13.
Maintenance validation (2026-10-19, keepalive base refresh)
- Synchronized main through its 0.46.5 keepalive release while retaining the authored 0.47.0 version and user-agent. Manual conflict resolution touched only the changelog and version file; main runtime and test changes merged automatically.
- Local validation: 419 unit tests and 71 contract tests passed (one existing expected unit failure). Four localhost socket tests needed bind permission and passed without source changes.
- Exact maintenance-head CI: https://github.com/Unstructured-IO/unstructured-python-client/actions/runs/39329146842.
Review follow-up (2026-10-20)
- Added
failure_category / failure_reason to JobNodeDetails with a new PreflightFailureCategory enum, and dropped both from the drift baseline. A new contract test covers a known category, an unknown category (plain str) and a passing node (both null); it passes on 3.11, 3.12 and 3.13.
- Removed the
JobStatus / JobProcessingStatus entries from overlay_client.yaml. Nothing reads the overlay since the generator was removed, and x-speakeasy-unknown-values would describe the OpenEnumMeta style, not the union shipped here.
make test-unit 419 passed, make test-contract 72 passed, make lint clean, make check-spec-drift clean against the live specs.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
…(0.47.0)
- JobStatus and JobProcessingStatus gain REJECTED. JobInformation.status and
JobDetails.processing_status accept unrecognized values as plain str.
- skip_preflight on CreateWorkflow, UpdateWorkflow and WorkflowInformation.
- scripts/check_spec_drift.py plus a weekly workflow that flags API fields and
enum values the SDK models do not cover.
Refs DTPL-696
Co-Authored-By: Claude Opus 5.5 <[email protected]>
cubic-dev-ai
Bot
left a comment
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0 issues found across 2 files (changes from recent commits).
Shadow auto-approve: would not auto-approve. This PR does not meet the repository auto-approval settings.
View guided diff | Re-trigger cubic
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Merge main while retaining the authored 0.47.0 feature release and user-agent.
Keep the full 0.46.5 keepalive changelog and prior release history verbatim.
All runtime and test changes merge automatically.
Validated 419 unit tests and 71 contract tests. Four localhost socket tests
needed bind permission and passed without source changes.
Refs DTPL-696
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving with one real ask and two nits.
The contract checks out against platform-api main and the live spec: REJECTED is spelled the same on both enums, create treats null/false as one state, update treats null as unchanged, and the SDK only puts skip_preflight on the wire when it's set. Reverting the model files makes the new contract tests fail, so they're testing the change. 419 unit / 71 contract pass locally on the head.
The ask: a caller who gets JobStatus.REJECTED still can't find out why. The server only puts the reason on each node of /details (failure_category, failure_reason), JobNodeDetails doesn't have either field, and pydantic drops them. JobDetails.message is only set when that detail is missing. So we fixed the crash, but the reason still isn't reachable. I'd add both fields to JobNodeDetails here (failure_category as Union[PreflightFailureCategory, UnrecognizedStr], same pattern as status) and drop them from the baseline. If you'd rather do it as a follow-up, say so in the body, because right now that gap only shows up in spec_drift_baseline.json.
Nits:
- The body still says the 0.46.3 split-PDF fix is folded into 0.47.0, and that's no longer true now that main ships 0.46.3 on its own. The first Validation block also still says 324/74.
- The overlay_client.yaml entries for JobStatus/JobProcessingStatus are dead now that the generator is gone, and x-speakeasy-unknown-values would give the OpenEnumMeta style rather than the Union you actually shipped. I'd drop them.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
…(DTPL-696)
Drop the dead JobStatus/JobProcessingStatus overlay entries; the generator
that read them is gone and the shipped models use a Union instead.
cubic-dev-ai
Bot
left a comment
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All reported issues were addressed across 9 files (changes from recent commits).
Shadow auto-approve: would not auto-approve because issues were found. Tip: Review your code locally with the cubic CLI to iterate faster.
View guided diff | Re-trigger cubic
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Reconcile release notes and versions without changing authored behavior.
Retain main dependency updates and the exact certifi lock record.
All nonmetadata files equal the automatic merge of main.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed exact head 4aeb58adb1d4d6c9da34684b50cafeb55dfb62ae with GPT Pro. No actionable defects found.
Known job statuses retain their enum identity; future values remain strings. Rejection diagnostics and workflow skip_preflight serialization have meaningful contract coverage. The prior inline-enum drift, fetch-failure reporting, and overlapping-run findings are addressed in the current source.
All 20 reported checks on this head passed. The scheduled spec-drift workflow has no execution result in that rollup. No local tests were run.
(authored by codex)
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
CyMule
added a commit
that referenced
this pull request
Nov 5, 2026
…365)
## What
The changelog now describes everything 0.47.0 will ship. 0.46.5 and
0.46.6 were never tagged or published (PyPI's latest is 0.46.4), so
their notes move into the 0.47.0 Fixes section:
```
Before After
## 0.47.0 ## 0.47.0
## 0.46.6 (never shipped) Features: error verdict attributes, skip_preflight
## 0.46.5 (never shipped) Fixes: REJECTED jobs, failure_category/reason,
## 0.46.4 certifi bump, TCP keepalive
## 0.46.4
```
No code changes. `_version.py` is already 0.47.0.
## Why
SDK users on 0.46.4 get a `ResponseValidationError` whenever a job in a
response is REJECTED, and one rejected job fails a whole `list_jobs`
page. The fix (#356) is on main but has not been released. This PR is
the last step before publishing GitHub release `v0.47.0`, which triggers
the PyPI Release workflow. Without it, the 0.46.5 and 0.46.6 changes
would be listed under versions that never existed.
## Validation
Smoke test on SND `nick-dtpl-885` with preflight enforcing, against a
REJECTED job:
| | `list_jobs` | `get_job` | `get_job_details` |
|---|---|---|---|
| 0.46.4 (PyPI) | `ResponseValidationError` | `ResponseValidationError`
| `ResponseValidationError` |
| 0.47.0 (main) | parses, status `REJECTED` | parses, status `REJECTED`
| parses, node `failure_category` set |
Part of DTPL-883.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/Unstructured-IO/unstructured-python-client/pull/365?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|