From 7e65416edeec1409a11cc6f55c752f9a0199668b Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Tue, 19 Aug 2025 03:11:21 +1000 Subject: [PATCH] Add test cases for more file input types Also makes lmstudio.LocalFileData available for type hinting purposes. Follow to #148 to add #46 test cases --- src/lmstudio/history.py | 1 + tests/async/test_images_async.py | 52 +++++++++++++++----------------- tests/sync/test_images_sync.py | 51 +++++++++++++++---------------- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/src/lmstudio/history.py b/src/lmstudio/history.py index 5fe7bd9..4de2402 100644 --- a/src/lmstudio/history.py +++ b/src/lmstudio/history.py @@ -78,6 +78,7 @@ "FileHandleDict", "FileHandleInput", "FileType", + "LocalFileInput", "SystemPrompt", "SystemPromptContent", "ToolCallRequest", diff --git a/tests/async/test_images_async.py b/tests/async/test_images_async.py index 8535076..65e2816 100644 --- a/tests/async/test_images_async.py +++ b/tests/async/test_images_async.py @@ -7,7 +7,7 @@ from io import BytesIO -from lmstudio import AsyncClient, Chat, FileHandle, LMStudioServerError +from lmstudio import AsyncClient, Chat, FileHandle, LMStudioServerError, LocalFileInput from ..support import ( EXPECTED_VLM_ID, @@ -17,28 +17,44 @@ check_sdk_error, ) +_IMAGE_DATA = IMAGE_FILEPATH.read_bytes() + +_FILE_INPUT_CASES: list[tuple[str, LocalFileInput]] = [ + ("filesystem path", IMAGE_FILEPATH), + ("bytes IO stream", BytesIO(_IMAGE_DATA)), + ("raw bytes", _IMAGE_DATA), + ("mutable buffer", bytearray(_IMAGE_DATA)), + ("memoryview", memoryview(_IMAGE_DATA)), +] +_FILE_INPUT_CASE_IDS = [case[0] for case in _FILE_INPUT_CASES] + @pytest.mark.asyncio @pytest.mark.lmstudio -async def test_upload_from_pathlike_async(caplog: LogCap) -> None: +@pytest.mark.parametrize( + "input_kind,file_input", _FILE_INPUT_CASES, ids=_FILE_INPUT_CASE_IDS +) +async def test_prepare_async( + caplog: LogCap, input_kind: str, file_input: LocalFileInput +) -> None: caplog.set_level(logging.DEBUG) async with AsyncClient() as client: session = client.files - file = await session._prepare_file(IMAGE_FILEPATH) + file = await session._prepare_file(file_input) assert file assert isinstance(file, FileHandle) - logging.info(f"Uploaded file: {file}") - image = await session.prepare_image(IMAGE_FILEPATH) + logging.info(f"Uploaded file from {input_kind}: {file}") + image = await session.prepare_image(file_input) assert image assert isinstance(image, FileHandle) - logging.info(f"Uploaded image: {image}") + logging.info(f"Uploaded image from {input_kind}: {image}") # Even with the same data uploaded, assigned identifiers should differ assert image != file @pytest.mark.asyncio @pytest.mark.lmstudio -async def test_upload_from_file_obj_async(caplog: LogCap) -> None: +async def test_prepare_from_file_obj_async(caplog: LogCap) -> None: caplog.set_level(logging.DEBUG) async with AsyncClient() as client: session = client.files @@ -46,30 +62,12 @@ async def test_upload_from_file_obj_async(caplog: LogCap) -> None: file = await session._prepare_file(f) assert file assert isinstance(file, FileHandle) - logging.info(f"Uploaded file: {file}") + logging.info(f"Uploaded file from file object: {file}") with open(IMAGE_FILEPATH, "rb") as f: image = await session.prepare_image(f) assert image assert isinstance(image, FileHandle) - logging.info(f"Uploaded image: {image}") - # Even with the same data uploaded, assigned identifiers should differ - assert image != file - - -@pytest.mark.asyncio -@pytest.mark.lmstudio -async def test_upload_from_bytesio_async(caplog: LogCap) -> None: - caplog.set_level(logging.DEBUG) - async with AsyncClient() as client: - session = client.files - file = await session._prepare_file(BytesIO(IMAGE_FILEPATH.read_bytes())) - assert file - assert isinstance(file, FileHandle) - logging.info(f"Uploaded file: {file}") - image = await session.prepare_image(BytesIO(IMAGE_FILEPATH.read_bytes())) - assert image - assert isinstance(image, FileHandle) - logging.info(f"Uploaded image: {image}") + logging.info(f"Uploaded image from file object: {image}") # Even with the same data uploaded, assigned identifiers should differ assert image != file diff --git a/tests/sync/test_images_sync.py b/tests/sync/test_images_sync.py index b944b40..4661d8a 100644 --- a/tests/sync/test_images_sync.py +++ b/tests/sync/test_images_sync.py @@ -14,7 +14,7 @@ from io import BytesIO -from lmstudio import Client, Chat, FileHandle, LMStudioServerError +from lmstudio import Client, Chat, FileHandle, LMStudioServerError, LocalFileInput from ..support import ( EXPECTED_VLM_ID, @@ -24,26 +24,42 @@ check_sdk_error, ) +_IMAGE_DATA = IMAGE_FILEPATH.read_bytes() + +_FILE_INPUT_CASES: list[tuple[str, LocalFileInput]] = [ + ("filesystem path", IMAGE_FILEPATH), + ("bytes IO stream", BytesIO(_IMAGE_DATA)), + ("raw bytes", _IMAGE_DATA), + ("mutable buffer", bytearray(_IMAGE_DATA)), + ("memoryview", memoryview(_IMAGE_DATA)), +] +_FILE_INPUT_CASE_IDS = [case[0] for case in _FILE_INPUT_CASES] + @pytest.mark.lmstudio -def test_upload_from_pathlike_sync(caplog: LogCap) -> None: +@pytest.mark.parametrize( + "input_kind,file_input", _FILE_INPUT_CASES, ids=_FILE_INPUT_CASE_IDS +) +def test_prepare_sync( + caplog: LogCap, input_kind: str, file_input: LocalFileInput +) -> None: caplog.set_level(logging.DEBUG) with Client() as client: session = client.files - file = session._prepare_file(IMAGE_FILEPATH) + file = session._prepare_file(file_input) assert file assert isinstance(file, FileHandle) - logging.info(f"Uploaded file: {file}") - image = session.prepare_image(IMAGE_FILEPATH) + logging.info(f"Uploaded file from {input_kind}: {file}") + image = session.prepare_image(file_input) assert image assert isinstance(image, FileHandle) - logging.info(f"Uploaded image: {image}") + logging.info(f"Uploaded image from {input_kind}: {image}") # Even with the same data uploaded, assigned identifiers should differ assert image != file @pytest.mark.lmstudio -def test_upload_from_file_obj_sync(caplog: LogCap) -> None: +def test_prepare_from_file_obj_sync(caplog: LogCap) -> None: caplog.set_level(logging.DEBUG) with Client() as client: session = client.files @@ -51,29 +67,12 @@ def test_upload_from_file_obj_sync(caplog: LogCap) -> None: file = session._prepare_file(f) assert file assert isinstance(file, FileHandle) - logging.info(f"Uploaded file: {file}") + logging.info(f"Uploaded file from file object: {file}") with open(IMAGE_FILEPATH, "rb") as f: image = session.prepare_image(f) assert image assert isinstance(image, FileHandle) - logging.info(f"Uploaded image: {image}") - # Even with the same data uploaded, assigned identifiers should differ - assert image != file - - -@pytest.mark.lmstudio -def test_upload_from_bytesio_sync(caplog: LogCap) -> None: - caplog.set_level(logging.DEBUG) - with Client() as client: - session = client.files - file = session._prepare_file(BytesIO(IMAGE_FILEPATH.read_bytes())) - assert file - assert isinstance(file, FileHandle) - logging.info(f"Uploaded file: {file}") - image = session.prepare_image(BytesIO(IMAGE_FILEPATH.read_bytes())) - assert image - assert isinstance(image, FileHandle) - logging.info(f"Uploaded image: {image}") + logging.info(f"Uploaded image from file object: {image}") # Even with the same data uploaded, assigned identifiers should differ assert image != file