Commit 3480e506
Changed files (5)
src/openai/_models.py
@@ -62,7 +62,7 @@ from ._compat import (
from ._constants import RAW_RESPONSE_HEADER
if TYPE_CHECKING:
- from pydantic_core.core_schema import ModelField, ModelFieldsSchema
+ from pydantic_core.core_schema import ModelField, LiteralSchema, ModelFieldsSchema
__all__ = ["BaseModel", "GenericModel"]
@@ -251,7 +251,9 @@ class BaseModel(pydantic.BaseModel):
exclude_defaults: bool = False,
exclude_none: bool = False,
round_trip: bool = False,
- warnings: bool = True,
+ warnings: bool | Literal["none", "warn", "error"] = True,
+ context: dict[str, Any] | None = None,
+ serialize_as_any: bool = False,
) -> dict[str, Any]:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump
@@ -279,6 +281,10 @@ class BaseModel(pydantic.BaseModel):
raise ValueError("round_trip is only supported in Pydantic v2")
if warnings != True:
raise ValueError("warnings is only supported in Pydantic v2")
+ if context is not None:
+ raise ValueError("context is only supported in Pydantic v2")
+ if serialize_as_any != False:
+ raise ValueError("serialize_as_any is only supported in Pydantic v2")
return super().dict( # pyright: ignore[reportDeprecated]
include=include,
exclude=exclude,
@@ -300,7 +306,9 @@ class BaseModel(pydantic.BaseModel):
exclude_defaults: bool = False,
exclude_none: bool = False,
round_trip: bool = False,
- warnings: bool = True,
+ warnings: bool | Literal["none", "warn", "error"] = True,
+ context: dict[str, Any] | None = None,
+ serialize_as_any: bool = False,
) -> str:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json
@@ -324,6 +332,10 @@ class BaseModel(pydantic.BaseModel):
raise ValueError("round_trip is only supported in Pydantic v2")
if warnings != True:
raise ValueError("warnings is only supported in Pydantic v2")
+ if context is not None:
+ raise ValueError("context is only supported in Pydantic v2")
+ if serialize_as_any != False:
+ raise ValueError("serialize_as_any is only supported in Pydantic v2")
return super().json( # type: ignore[reportDeprecated]
indent=indent,
include=include,
@@ -550,7 +562,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any,
field_schema = field["schema"]
if field_schema["type"] == "literal":
- for entry in field_schema["expected"]:
+ for entry in cast("LiteralSchema", field_schema)["expected"]:
if isinstance(entry, str):
mapping[entry] = variant
else:
tests/test_models.py
@@ -31,7 +31,7 @@ def test_directly_nested_model() -> None:
# mismatched types
m = NestedModel.construct(nested="hello!")
- assert m.nested == "hello!"
+ assert cast(Any, m.nested) == "hello!"
def test_optional_nested_model() -> None:
@@ -48,7 +48,7 @@ def test_optional_nested_model() -> None:
# mismatched types
m3 = NestedModel.construct(nested={"foo"})
assert isinstance(cast(Any, m3.nested), set)
- assert m3.nested == {"foo"}
+ assert cast(Any, m3.nested) == {"foo"}
def test_list_nested_model() -> None:
@@ -323,7 +323,7 @@ def test_list_of_unions() -> None:
assert len(m.items) == 2
assert isinstance(m.items[0], Submodel1)
assert m.items[0].level == -1
- assert m.items[1] == 156
+ assert cast(Any, m.items[1]) == 156
def test_union_of_lists() -> None:
@@ -355,7 +355,7 @@ def test_union_of_lists() -> None:
assert len(m.items) == 2
assert isinstance(m.items[0], SubModel1)
assert m.items[0].level == -1
- assert m.items[1] == 156
+ assert cast(Any, m.items[1]) == 156
def test_dict_of_union() -> None:
tests/test_transform.py
@@ -260,20 +260,22 @@ class MyModel(BaseModel):
@parametrize
@pytest.mark.asyncio
async def test_pydantic_model_to_dictionary(use_async: bool) -> None:
- assert await transform(MyModel(foo="hi!"), Any, use_async) == {"foo": "hi!"}
- assert await transform(MyModel.construct(foo="hi!"), Any, use_async) == {"foo": "hi!"}
+ assert cast(Any, await transform(MyModel(foo="hi!"), Any, use_async)) == {"foo": "hi!"}
+ assert cast(Any, await transform(MyModel.construct(foo="hi!"), Any, use_async)) == {"foo": "hi!"}
@parametrize
@pytest.mark.asyncio
async def test_pydantic_empty_model(use_async: bool) -> None:
- assert await transform(MyModel.construct(), Any, use_async) == {}
+ assert cast(Any, await transform(MyModel.construct(), Any, use_async)) == {}
@parametrize
@pytest.mark.asyncio
async def test_pydantic_unknown_field(use_async: bool) -> None:
- assert await transform(MyModel.construct(my_untyped_field=True), Any, use_async) == {"my_untyped_field": True}
+ assert cast(Any, await transform(MyModel.construct(my_untyped_field=True), Any, use_async)) == {
+ "my_untyped_field": True
+ }
@parametrize
@@ -285,7 +287,7 @@ async def test_pydantic_mismatched_types(use_async: bool) -> None:
params = await transform(model, Any, use_async)
else:
params = await transform(model, Any, use_async)
- assert params == {"foo": True}
+ assert cast(Any, params) == {"foo": True}
@parametrize
@@ -297,7 +299,7 @@ async def test_pydantic_mismatched_object_type(use_async: bool) -> None:
params = await transform(model, Any, use_async)
else:
params = await transform(model, Any, use_async)
- assert params == {"foo": {"hello": "world"}}
+ assert cast(Any, params) == {"foo": {"hello": "world"}}
class ModelNestedObjects(BaseModel):
@@ -309,7 +311,7 @@ class ModelNestedObjects(BaseModel):
async def test_pydantic_nested_objects(use_async: bool) -> None:
model = ModelNestedObjects.construct(nested={"foo": "stainless"})
assert isinstance(model.nested, MyModel)
- assert await transform(model, Any, use_async) == {"nested": {"foo": "stainless"}}
+ assert cast(Any, await transform(model, Any, use_async)) == {"nested": {"foo": "stainless"}}
class ModelWithDefaultField(BaseModel):
@@ -325,19 +327,19 @@ async def test_pydantic_default_field(use_async: bool) -> None:
model = ModelWithDefaultField.construct()
assert model.with_none_default is None
assert model.with_str_default == "foo"
- assert await transform(model, Any, use_async) == {}
+ assert cast(Any, await transform(model, Any, use_async)) == {}
# should be included when the default value is explicitly given
model = ModelWithDefaultField.construct(with_none_default=None, with_str_default="foo")
assert model.with_none_default is None
assert model.with_str_default == "foo"
- assert await transform(model, Any, use_async) == {"with_none_default": None, "with_str_default": "foo"}
+ assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": None, "with_str_default": "foo"}
# should be included when a non-default value is explicitly given
model = ModelWithDefaultField.construct(with_none_default="bar", with_str_default="baz")
assert model.with_none_default == "bar"
assert model.with_str_default == "baz"
- assert await transform(model, Any, use_async) == {"with_none_default": "bar", "with_str_default": "baz"}
+ assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": "bar", "with_str_default": "baz"}
class TypedDictIterableUnion(TypedDict):
requirements-dev.lock
@@ -24,7 +24,7 @@ attrs==23.1.0
azure-core==1.30.1
# via azure-identity
azure-identity==1.15.0
-black==24.4.0
+black==24.4.2
# via inline-snapshot
certifi==2023.7.22
# via httpcore
@@ -39,7 +39,7 @@ click==8.1.7
# via inline-snapshot
colorlog==6.7.0
# via nox
-cryptography==42.0.5
+cryptography==42.0.7
# via azure-identity
# via msal
# via pyjwt
@@ -111,9 +111,9 @@ py==1.11.0
# via pytest
pycparser==2.22
# via cffi
-pydantic==2.4.2
+pydantic==2.7.1
# via openai
-pydantic-core==2.10.1
+pydantic-core==2.18.2
# via pydantic
pyjwt==2.8.0
# via msal
requirements.lock
@@ -33,13 +33,13 @@ numpy==1.26.4
# via openai
# via pandas
# via pandas-stubs
-pandas==2.2.1
+pandas==2.2.2
# via openai
pandas-stubs==2.2.1.240316
# via openai
-pydantic==2.4.2
+pydantic==2.7.1
# via openai
-pydantic-core==2.10.1
+pydantic-core==2.18.2
# via pydantic
python-dateutil==2.9.0.post0
# via pandas
@@ -53,7 +53,7 @@ sniffio==1.3.0
# via openai
tqdm==4.66.1
# via openai
-types-pytz==2024.1.0.20240203
+types-pytz==2024.1.0.20240417
# via pandas-stubs
typing-extensions==4.8.0
# via openai