Commit 44ac1cef

Stainless Bot <dev+git@stainlessapi.com>
2024-10-28 20:28:17
chore(internal): bump pytest to v8 & pydantic (#1829)
1 parent e1b2f82
src/openai/lib/streaming/chat/_completions.py
@@ -23,7 +23,7 @@ from ._events import (
     FunctionToolCallArgumentsDeltaEvent,
 )
 from .._deltas import accumulate_delta
-from ...._types import NOT_GIVEN, NotGiven
+from ...._types import NOT_GIVEN, IncEx, NotGiven
 from ...._utils import is_given, consume_sync_iterator, consume_async_iterator
 from ...._compat import model_dump
 from ...._models import build, construct_type
@@ -352,13 +352,17 @@ class ChatCompletionStreamState(Generic[ResponseFormatT]):
                                     # we don't want to serialise / deserialise our custom properties
                                     # as they won't appear in the delta and we don't want to have to
                                     # continuosly reparse the content
-                                    exclude={
-                                        "parsed": True,
-                                        "tool_calls": {
-                                            idx: {"function": {"parsed_arguments": True}}
-                                            for idx, _ in enumerate(choice_snapshot.message.tool_calls or [])
+                                    exclude=cast(
+                                        # cast required as mypy isn't smart enough to infer `True` here to `Literal[True]`
+                                        IncEx,
+                                        {
+                                            "parsed": True,
+                                            "tool_calls": {
+                                                idx: {"function": {"parsed_arguments": True}}
+                                                for idx, _ in enumerate(choice_snapshot.message.tool_calls or [])
+                                            },
                                         },
-                                    },
+                                    ),
                                 ),
                             ),
                             cast("dict[object, object]", choice.delta.to_dict()),
src/openai/_compat.py
@@ -133,7 +133,7 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str:
 def model_dump(
     model: pydantic.BaseModel,
     *,
-    exclude: IncEx = None,
+    exclude: IncEx | None = None,
     exclude_unset: bool = False,
     exclude_defaults: bool = False,
     warnings: bool = True,
src/openai/_models.py
@@ -201,7 +201,7 @@ class BaseModel(pydantic.BaseModel):
     # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836.
     @classmethod
     @override
-    def construct(
+    def construct(  # pyright: ignore[reportIncompatibleMethodOverride]
         cls: Type[ModelT],
         _fields_set: set[str] | None = None,
         **values: object,
@@ -273,8 +273,8 @@ class BaseModel(pydantic.BaseModel):
             self,
             *,
             mode: Literal["json", "python"] | str = "python",
-            include: IncEx = None,
-            exclude: IncEx = None,
+            include: IncEx | None = None,
+            exclude: IncEx | None = None,
             by_alias: bool = False,
             exclude_unset: bool = False,
             exclude_defaults: bool = False,
@@ -328,8 +328,8 @@ class BaseModel(pydantic.BaseModel):
             self,
             *,
             indent: int | None = None,
-            include: IncEx = None,
-            exclude: IncEx = None,
+            include: IncEx | None = None,
+            exclude: IncEx | None = None,
             by_alias: bool = False,
             exclude_unset: bool = False,
             exclude_defaults: bool = False,
src/openai/_types.py
@@ -16,7 +16,7 @@ from typing import (
     Optional,
     Sequence,
 )
-from typing_extensions import Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable
+from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable
 
 import httpx
 import pydantic
@@ -195,7 +195,9 @@ StrBytesIntFloat = Union[str, bytes, int, float]
 
 # Note: copied from Pydantic
 # https://github.com/pydantic/pydantic/blob/32ea570bf96e84234d2992e1ddf40ab8a565925a/pydantic/main.py#L49
-IncEx: TypeAlias = "set[int] | set[str] | dict[int, Any] | dict[str, Any] | None"
+IncEx: TypeAlias = Union[
+    Set[int], Set[str], Mapping[int, Union["IncEx", Literal[True]]], Mapping[str, Union["IncEx", Literal[True]]]
+]
 
 PostParser = Callable[[Any], Any]
 
tests/lib/test_old_api.py
@@ -6,7 +6,7 @@ from openai.lib._old_api import APIRemovedInV1
 
 def test_basic_attribute_access_works() -> None:
     for attr in dir(openai):
-        dir(getattr(openai, attr))
+        getattr(openai, attr)
 
 
 def test_helpful_error_is_raised() -> None:
tests/conftest.py
@@ -1,11 +1,11 @@
 from __future__ import annotations
 
 import os
-import asyncio
 import logging
 from typing import TYPE_CHECKING, Iterator, AsyncIterator
 
 import pytest
+from pytest_asyncio import is_async_test
 
 from openai import OpenAI, AsyncOpenAI
 
@@ -17,11 +17,13 @@ pytest.register_assert_rewrite("tests.utils")
 logging.getLogger("openai").setLevel(logging.DEBUG)
 
 
-@pytest.fixture(scope="session")
-def event_loop() -> Iterator[asyncio.AbstractEventLoop]:
-    loop = asyncio.new_event_loop()
-    yield loop
-    loop.close()
+# automatically add `pytest.mark.asyncio()` to all of our async tests
+# so we don't have to add that boilerplate everywhere
+def pytest_collection_modifyitems(items: list[pytest.Function]) -> None:
+    pytest_asyncio_tests = (item for item in items if is_async_test(item))
+    session_scope_marker = pytest.mark.asyncio(loop_scope="session")
+    for async_test in pytest_asyncio_tests:
+        async_test.add_marker(session_scope_marker, append=False)
 
 
 base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
requirements-dev.lock
@@ -18,14 +18,13 @@ argcomplete==3.1.2
     # via nox
 asttokens==2.4.1
     # via inline-snapshot
-attrs==23.1.0
+attrs==24.2.0
     # via outcome
-    # via pytest
     # via trio
-azure-core==1.30.1
+azure-core==1.31.0
     # via azure-identity
-azure-identity==1.15.0
-black==24.4.2
+azure-identity==1.19.0
+black==24.10.0
     # via inline-snapshot
 certifi==2023.7.22
     # via httpcore
@@ -49,10 +48,11 @@ distlib==0.3.7
     # via virtualenv
 distro==1.8.0
     # via openai
-exceptiongroup==1.1.3
+exceptiongroup==1.2.2
     # via anyio
+    # via pytest
     # via trio
-executing==2.0.1
+executing==2.1.0
     # via inline-snapshot
 filelock==3.12.4
     # via virtualenv
@@ -78,7 +78,7 @@ markdown-it-py==3.0.0
     # via rich
 mdurl==0.1.2
     # via markdown-it-py
-msal==1.29.0
+msal==1.31.0
     # via azure-identity
     # via msal-extensions
 msal-extensions==1.2.0
@@ -109,26 +109,24 @@ pathspec==0.12.1
 platformdirs==3.11.0
     # via black
     # via virtualenv
-pluggy==1.3.0
+pluggy==1.5.0
     # via pytest
-portalocker==2.8.2
+portalocker==2.10.1
     # via msal-extensions
-py==1.11.0
-    # via pytest
 pycparser==2.22
     # via cffi
-pydantic==2.7.1
+pydantic==2.9.2
     # via openai
-pydantic-core==2.18.2
+pydantic-core==2.23.4
     # via pydantic
 pygments==2.18.0
     # via rich
 pyjwt==2.8.0
     # via msal
 pyright==1.1.380
-pytest==7.1.1
+pytest==8.3.3
     # via pytest-asyncio
-pytest-asyncio==0.21.1
+pytest-asyncio==0.24.0
 python-dateutil==2.8.2
     # via pandas
     # via time-machine
@@ -158,21 +156,22 @@ sortedcontainers==2.4.0
 time-machine==2.9.0
 toml==0.10.2
     # via inline-snapshot
-tomli==2.0.1
+tomli==2.0.2
     # via black
     # via mypy
     # via pytest
-tqdm==4.66.1
+tqdm==4.66.5
     # via openai
-trio==0.22.2
-types-pyaudio==0.2.16.20240106
-types-pytz==2024.1.0.20240417
+trio==0.27.0
+types-pyaudio==0.2.16.20240516
+types-pytz==2024.2.0.20241003
     # via pandas-stubs
 types-toml==0.10.8.20240310
     # via inline-snapshot
-types-tqdm==4.66.0.2
+types-tqdm==4.66.0.20240417
 typing-extensions==4.12.2
     # via azure-core
+    # via azure-identity
     # via black
     # via mypy
     # via openai
requirements.lock
@@ -19,7 +19,7 @@ certifi==2023.7.22
     # via httpx
 distro==1.8.0
     # via openai
-exceptiongroup==1.1.3
+exceptiongroup==1.2.2
     # via anyio
 h11==0.14.0
     # via httpcore
@@ -30,19 +30,19 @@ httpx==0.25.2
 idna==3.4
     # via anyio
     # via httpx
-jiter==0.5.0
+jiter==0.6.1
     # via openai
-numpy==1.26.4
+numpy==2.0.2
     # via openai
     # via pandas
     # via pandas-stubs
-pandas==2.2.2
+pandas==2.2.3
     # via openai
-pandas-stubs==2.2.1.240316
+pandas-stubs==2.2.2.240807
     # via openai
-pydantic==2.7.1
+pydantic==2.9.2
     # via openai
-pydantic-core==2.18.2
+pydantic-core==2.23.4
     # via pydantic
 python-dateutil==2.9.0.post0
     # via pandas
@@ -54,9 +54,9 @@ sniffio==1.3.0
     # via anyio
     # via httpx
     # via openai
-tqdm==4.66.1
+tqdm==4.66.5
     # via openai
-types-pytz==2024.1.0.20240417
+types-pytz==2024.2.0.20241003
     # via pandas-stubs
 typing-extensions==4.12.2
     # via openai