mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-06 10:21:32 +00:00
fix(image_edits): drop _RewindableImage to prevent infinite multipart upload
The _RewindableImage(BytesIO) wrapper auto-rewound on every read after
EOF, which made the OpenAI SDK's multipart upload writer read the same
bytes forever instead of seeing EOF. Workers OOM'd / SIGKILL'd:
[gw0] node down: Not properly terminated
replacing crashed worker gw0
...
worker 'gw1' crashed while running
'tests/image_gen_tests/test_image_edits.py::TestOpenAIImageEditGPTImage1::test_openai_image_edit_litellm_sdk[False]'
The auto-rewind was added defensively for parametrized + flaky-retried
tests, but BaseLLMImageEditTest::test_openai_image_edit_litellm_sdk
already calls get_base_image_edit_call_args() once per invocation and
that helper now constructs fresh streams via _make_test_images(), so
rewinding inside the stream is unnecessary. Replace with plain BytesIO
seeded with the cached image bytes.
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
This commit is contained in:
co-authored by
Mateo Wang
parent
ba0f4c1566
commit
b13ae8de50
@@ -118,36 +118,26 @@ _ISHAAN_GITHUB_BYTES = _read_image_bytes("ishaan_github.png")
|
||||
_LITELLM_SITE_BYTES = _read_image_bytes("litellm_site.png")
|
||||
|
||||
|
||||
class _RewindableImage(BytesIO):
|
||||
"""``BytesIO`` that re-seeks to 0 on read after exhaustion.
|
||||
|
||||
The OpenAI / Azure SDKs read the file pointer once per request. When we
|
||||
pass the *same* object to a parametrized or retried test, the second
|
||||
invocation must see the same bytes from offset 0, not EOF.
|
||||
"""
|
||||
|
||||
def read(self, size=-1):
|
||||
if self.tell() and self.tell() >= len(self.getvalue()):
|
||||
self.seek(0)
|
||||
return super().read(size)
|
||||
|
||||
|
||||
def _make_test_images() -> list:
|
||||
"""Return a fresh pair of rewindable image streams.
|
||||
"""Return a fresh pair of image streams seeded with the fixture bytes.
|
||||
|
||||
Use this everywhere you'd previously have used the module-level
|
||||
``TEST_IMAGES``. Each call returns brand new ``BytesIO`` objects whose
|
||||
file pointers start at 0, so multipart uploads encode the full image
|
||||
bytes on every test invocation.
|
||||
bytes on every test invocation. Parametrized and ``flaky``-retried
|
||||
test methods call ``get_base_image_edit_call_args`` once per
|
||||
invocation, so a fresh stream per call is sufficient — the factory
|
||||
must not auto-rewind on EOF or the SDK's multipart writer will read
|
||||
the same bytes forever (worker OOM).
|
||||
"""
|
||||
return [
|
||||
_RewindableImage(_ISHAAN_GITHUB_BYTES),
|
||||
_RewindableImage(_LITELLM_SITE_BYTES),
|
||||
BytesIO(_ISHAAN_GITHUB_BYTES),
|
||||
BytesIO(_LITELLM_SITE_BYTES),
|
||||
]
|
||||
|
||||
|
||||
def _make_single_test_image() -> BytesIO:
|
||||
return _RewindableImage(_ISHAAN_GITHUB_BYTES)
|
||||
return BytesIO(_ISHAAN_GITHUB_BYTES)
|
||||
|
||||
|
||||
def get_test_images_as_bytesio():
|
||||
|
||||
Reference in New Issue
Block a user