Skip to content

Commit bba25d5

Browse files
committed
feat(models)!: reject unknown fields on request models
Generated request models silently dropped unknown keyword arguments (pydantic's default extra='ignore'), so a typo or a field from a newer API never reached the server. scripts/patch_model_extra_forbid.py adds extra='forbid' to every model used as a request body and to the models nested in them, and the regenerate workflow re-applies it. Response models are untouched so a newer server still cannot break an older SDK. BREAKING CHANGE: constructing a request model with an unknown keyword now raises pydantic.ValidationError.
1 parent 46a7255 commit bba25d5

33 files changed

Lines changed: 376 additions & 0 deletions

‎.github/workflows/regenerate.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ jobs:
204204
- name: Patch missing-workspace guard into ApiClient
205205
run: python3 scripts/patch_workspace_guard.py
206206

207+
- name: Patch request models to reject unknown fields (extra=forbid)
208+
run: python3 scripts/patch_model_extra_forbid.py
209+
207210
# The API-token -> JWT key exchange is deprecated: the configured API token
208211
# is the bearer credential and goes on the wire verbatim. This check is the
209212
# inverse of the old "did the exchange survive?" guard — it fails if the

‎CHANGELOG.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3636

3737
### Changed
3838

39+
- **Breaking:** request models reject unknown fields. Every model used as a
40+
request body (`QueryRequest`, `LoadManagedTableRequest`,
41+
`CreateDatabaseRequest`, ... and the models nested in them) now carries
42+
`extra="forbid"`, so a misspelled keyword, or a field a newer API has that
43+
this SDK release does not know yet, raises `pydantic.ValidationError` at
44+
construction instead of being silently dropped from the request. Upgrade the
45+
SDK to use a new field. Response models are unchanged: unknown fields in
46+
server responses are still ignored, so a newer server never breaks an older
47+
SDK.
3948
- feat(query): add arrow ipc stream response format
4049
- chore(query): clarify write statement handling in dialect parameter
4150
- chore(indexes): clarify vector index constraints and algorithms

‎hotdata/models/add_managed_schema_request.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ class AddManagedSchemaRequest(BaseModel):
3636
populate_by_name=True,
3737
validate_assignment=True,
3838
protected_namespaces=(),
39+
# Hand-applied (scripts/patch_model_extra_forbid.py): this is a
40+
# request model, so an unknown keyword is a caller mistake (or a field
41+
# this SDK release does not know) and must not be dropped silently.
42+
extra="forbid",
3943
)
4044

4145

‎hotdata/models/add_managed_table_decl.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ class AddManagedTableDecl(BaseModel):
4040
populate_by_name=True,
4141
validate_assignment=True,
4242
protected_namespaces=(),
43+
# Hand-applied (scripts/patch_model_extra_forbid.py): this is a
44+
# request model, so an unknown keyword is a caller mistake (or a field
45+
# this SDK release does not know) and must not be dropped silently.
46+
extra="forbid",
4347
)
4448

4549

‎hotdata/models/add_managed_table_request.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ class AddManagedTableRequest(BaseModel):
4040
populate_by_name=True,
4141
validate_assignment=True,
4242
protected_namespaces=(),
43+
# Hand-applied (scripts/patch_model_extra_forbid.py): this is a
44+
# request model, so an unknown keyword is a caller mistake (or a field
45+
# this SDK release does not know) and must not be dropped silently.
46+
extra="forbid",
4347
)
4448

4549

‎hotdata/models/attach_database_catalog_request.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ class AttachDatabaseCatalogRequest(BaseModel):
3535
populate_by_name=True,
3636
validate_assignment=True,
3737
protected_namespaces=(),
38+
# Hand-applied (scripts/patch_model_extra_forbid.py): this is a
39+
# request model, so an unknown keyword is a caller mistake (or a field
40+
# this SDK release does not know) and must not be dropped silently.
41+
extra="forbid",
3842
)
3943

4044

‎hotdata/models/batch_create_upload_request.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ class BatchCreateUploadRequest(BaseModel):
3535
populate_by_name=True,
3636
validate_assignment=True,
3737
protected_namespaces=(),
38+
# Hand-applied (scripts/patch_model_extra_forbid.py): this is a
39+
# request model, so an unknown keyword is a caller mistake (or a field
40+
# this SDK release does not know) and must not be dropped silently.
41+
extra="forbid",
3842
)
3943

4044

‎hotdata/models/bulk_create_databases_request.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class BulkCreateDatabasesRequest(BaseModel):
4242
populate_by_name=True,
4343
validate_assignment=True,
4444
protected_namespaces=(),
45+
# Hand-applied (scripts/patch_model_extra_forbid.py): this is a
46+
# request model, so an unknown keyword is a caller mistake (or a field
47+
# this SDK release does not know) and must not be dropped silently.
48+
extra="forbid",
4549
)
4650

4751

‎hotdata/models/column_type_spec.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class ColumnTypeSpec(BaseModel):
3737
populate_by_name=True,
3838
validate_assignment=True,
3939
protected_namespaces=(),
40+
# Hand-applied (scripts/patch_model_extra_forbid.py): this is a
41+
# request model, so an unknown keyword is a caller mistake (or a field
42+
# this SDK release does not know) and must not be dropped silently.
43+
extra="forbid",
4044
)
4145

4246

‎hotdata/models/create_connection_request.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ class CreateConnectionRequest(BaseModel):
3838
populate_by_name=True,
3939
validate_assignment=True,
4040
protected_namespaces=(),
41+
# Hand-applied (scripts/patch_model_extra_forbid.py): this is a
42+
# request model, so an unknown keyword is a caller mistake (or a field
43+
# this SDK release does not know) and must not be dropped silently.
44+
extra="forbid",
4145
)
4246

4347

0 commit comments

Comments
 (0)