Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions src/openai/lib/streaming/_assistants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@
from ..._httpx2 import timeout_exceptions
from ..._models import construct_type
from ..._streaming import Stream, AsyncStream
from ...types.beta import AssistantStreamEvent
from ...types.beta.threads import (
Run,
Text,
Message,
ImageFile,
TextDelta,
MessageDelta,
MessageContent,
MessageContentDelta,
)
from ...types.beta.threads.runs import RunStep, ToolCall, RunStepDelta, ToolCallDelta

if TYPE_CHECKING:
from ...types.beta import AssistantStreamEvent
from ...types.beta.threads import (
Run,
Text,
Message,
ImageFile,
TextDelta,
MessageDelta,
MessageContent,
MessageContentDelta,
)
from ...types.beta.threads.runs import RunStep, ToolCall, RunStepDelta, ToolCallDelta


def _timeout_exceptions() -> tuple[type[Exception], ...]:
Expand Down Expand Up @@ -903,6 +905,8 @@ def accumulate_run_step(
return

if event.event == "thread.run.step.delta":
from ...types.beta.threads.runs import RunStep

data = event.data
snapshot = run_step_snapshots[data.id]

Expand All @@ -928,6 +932,8 @@ def accumulate_event(
current_message_snapshot: Message | None,
) -> tuple[Message | None, list[MessageContentDelta]]:
"""Returns a tuple of message snapshot and newly created text message deltas"""
from ...types.beta.threads import MessageContent

if event.event == "thread.message.created":
return event.data, []

Expand Down
35 changes: 35 additions & 0 deletions tests/lib/test_streaming_lazy_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from __future__ import annotations

import sys
import subprocess

import openai


def _modules_after_import_openai() -> set[str]:
"""Return the module names loaded by a bare `import openai` in a fresh interpreter."""
output = subprocess.run(
[
sys.executable,
"-c",
"import sys\nimport openai\nprint('\\n'.join(sys.modules))\n",
],
check=True,
capture_output=True,
text=True,
).stdout
return set(output.split())


def test_import_openai_does_not_load_beta_types() -> None:
# `openai.lib.streaming` only needs `openai.types.beta` for annotations and for two
# narrow runtime paths, so importing the package must not pull the namespace in.
modules = _modules_after_import_openai()

assert "openai" in modules
assert not [module for module in modules if module.startswith("openai.types.beta")]


def test_assistant_event_handlers_are_still_eagerly_exported() -> None:
assert openai.AssistantEventHandler.__name__ == "AssistantEventHandler"
assert openai.AsyncAssistantEventHandler.__name__ == "AsyncAssistantEventHandler"