fix: coerce by_alias to bool in model_dump to prevent TypeError with DEBUG logging#2940
fix: coerce by_alias to bool in model_dump to prevent TypeError with DEBUG logging#2940giulio-leone wants to merge 2 commits intoopenai:mainfrom
by_alias to bool in model_dump to prevent TypeError with DEBUG logging#2940Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4bd22da0f2
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
src/openai/_compat.py
Outdated
| # warnings are not supported in Pydantic v1 | ||
| warnings=True if PYDANTIC_V1 else warnings, | ||
| by_alias=by_alias, | ||
| by_alias=bool(by_alias), |
There was a problem hiding this comment.
Preserve tri-state
by_alias semantics in model_dump
Coercing by_alias with bool(by_alias) changes the meaning of the default None value from “use model default” to always False, so models that rely on alias serialization defaults (e.g., ConfigDict(serialize_by_alias=True) in Pydantic v2) will now silently emit field names instead of aliases when callers omit by_alias. This is a behavior regression from the previous pass-through and can produce incorrect serialized payloads in any call site using _compat.model_dump(..., by_alias=None) or the default.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch — updated the fix to omit by_alias entirely when None instead of coercing with bool(). This preserves tri-state semantics so models with ConfigDict(serialize_by_alias=True) keep their default alias behavior.
…TypeError `model_dump()` in `_compat.py` declares `by_alias: bool | None = None` but passes the value directly to Pydantic v2's `model_dump()`, which expects a `bool`. When `by_alias` is `None` (the default), pydantic-core's Rust serializer raises `TypeError: argument 'by_alias': 'NoneType' object cannot be converted to 'PyBool'`. This only manifests when DEBUG logging is enabled, because the affected call path is inside `_build_request()`'s `log.isEnabledFor(logging.DEBUG)` block. Omit `by_alias` from kwargs when `None` so Pydantic uses its model-level default (preserving tri-state semantics for models with `ConfigDict(serialize_by_alias=True)`), and only forward explicit `True`/`False` values. Fixes openai#2921 Signed-off-by: Giulio Leone <[email protected]>
4bd22da to
ccc9f17
Compare
|
Friendly ping — CI is green, tests pass, rebased on latest. Ready for review whenever convenient. Happy to address any feedback. 🙏 |
Only coerce to bool when by_alias is not None, avoiding loss of None vs False distinction in the v1 fallback code path.
Summary
Fixes #2921 —
model_dump()raisesTypeError: argument 'by_alias': 'NoneType' object cannot be converted to 'PyBool'when DEBUG logging is enabled.Root Cause
In
_compat.py,model_dump()declaresby_alias: bool | None = Nonebut passes the value directly to Pydantic v2'smodel_dump():Fix
Omit
by_aliasfrom kwargs whenNone, preserving Pydantic's model-level default (e.g.ConfigDict(serialize_by_alias=True)). Only forward explicitTrue/Falsevalues:This preserves tri-state semantics:
None→ Pydantic uses its model defaultTrue/False→ explicitly forwardedTests
Added
test_model_dump_by_alias_noneverifying:by_alias=None) worksby_alias=Noneworksby_alias=Falsestill forwarded correctly