openai/openai-python
Publicmirrored from https://github.com/openai/openai-pythonAvailable
tests/test_files.py
148lines · modecode
| 1 | from pathlib import Path |
| 2 | |
| 3 | import anyio |
| 4 | import pytest |
| 5 | from dirty_equals import IsDict, IsList, IsBytes, IsTuple |
| 6 | |
| 7 | from openai._files import to_httpx_files, deepcopy_with_paths, async_to_httpx_files |
| 8 | from openai._utils import extract_files |
| 9 | |
| 10 | readme_path = Path(__file__).parent.parent.joinpath("README.md") |
| 11 | |
| 12 | |
| 13 | def test_pathlib_includes_file_name() -> None: |
| 14 | result = to_httpx_files({"file": readme_path}) |
| 15 | print(result) |
| 16 | assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) |
| 17 | |
| 18 | |
| 19 | def test_tuple_input() -> None: |
| 20 | result = to_httpx_files([("file", readme_path)]) |
| 21 | print(result) |
| 22 | assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) |
| 23 | |
| 24 | |
| 25 | @pytest.mark.asyncio |
| 26 | async def test_async_pathlib_includes_file_name() -> None: |
| 27 | result = await async_to_httpx_files({"file": readme_path}) |
| 28 | print(result) |
| 29 | assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) |
| 30 | |
| 31 | |
| 32 | @pytest.mark.asyncio |
| 33 | async def test_async_supports_anyio_path() -> None: |
| 34 | result = await async_to_httpx_files({"file": anyio.Path(readme_path)}) |
| 35 | print(result) |
| 36 | assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) |
| 37 | |
| 38 | |
| 39 | @pytest.mark.asyncio |
| 40 | async def test_async_tuple_input() -> None: |
| 41 | result = await async_to_httpx_files([("file", readme_path)]) |
| 42 | print(result) |
| 43 | assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) |
| 44 | |
| 45 | |
| 46 | def test_string_not_allowed() -> None: |
| 47 | with pytest.raises(TypeError, match="Expected file types input to be a FileContent type or to be a tuple"): |
| 48 | to_httpx_files( |
| 49 | { |
| 50 | "file": "foo", # type: ignore |
| 51 | } |
| 52 | ) |
| 53 | |
| 54 | |
| 55 | def assert_different_identities(obj1: object, obj2: object) -> None: |
| 56 | assert obj1 == obj2 |
| 57 | assert obj1 is not obj2 |
| 58 | |
| 59 | |
| 60 | class TestDeepcopyWithPaths: |
| 61 | def test_copies_top_level_dict(self) -> None: |
| 62 | original = {"file": b"data", "other": "value"} |
| 63 | result = deepcopy_with_paths(original, [["file"]]) |
| 64 | assert_different_identities(result, original) |
| 65 | |
| 66 | def test_file_value_is_same_reference(self) -> None: |
| 67 | file_bytes = b"contents" |
| 68 | original = {"file": file_bytes} |
| 69 | result = deepcopy_with_paths(original, [["file"]]) |
| 70 | assert_different_identities(result, original) |
| 71 | assert result["file"] is file_bytes |
| 72 | |
| 73 | def test_list_popped_wholesale(self) -> None: |
| 74 | files = [b"f1", b"f2"] |
| 75 | original = {"files": files, "title": "t"} |
| 76 | result = deepcopy_with_paths(original, [["files", "<array>"]]) |
| 77 | assert_different_identities(result, original) |
| 78 | result_files = result["files"] |
| 79 | assert isinstance(result_files, list) |
| 80 | assert_different_identities(result_files, files) |
| 81 | |
| 82 | def test_nested_array_path_copies_list_and_elements(self) -> None: |
| 83 | elem1 = {"file": b"f1", "extra": 1} |
| 84 | elem2 = {"file": b"f2", "extra": 2} |
| 85 | original = {"items": [elem1, elem2]} |
| 86 | result = deepcopy_with_paths(original, [["items", "<array>", "file"]]) |
| 87 | assert_different_identities(result, original) |
| 88 | result_items = result["items"] |
| 89 | assert isinstance(result_items, list) |
| 90 | assert_different_identities(result_items, original["items"]) |
| 91 | assert_different_identities(result_items[0], elem1) |
| 92 | assert_different_identities(result_items[1], elem2) |
| 93 | |
| 94 | def test_empty_paths_returns_same_object(self) -> None: |
| 95 | original = {"foo": "bar"} |
| 96 | result = deepcopy_with_paths(original, []) |
| 97 | assert result is original |
| 98 | |
| 99 | def test_multiple_paths(self) -> None: |
| 100 | f1 = b"file1" |
| 101 | f2 = b"file2" |
| 102 | original = {"a": f1, "b": f2, "c": "unchanged"} |
| 103 | result = deepcopy_with_paths(original, [["a"], ["b"]]) |
| 104 | assert_different_identities(result, original) |
| 105 | assert result["a"] is f1 |
| 106 | assert result["b"] is f2 |
| 107 | assert result["c"] is original["c"] |
| 108 | |
| 109 | def test_extract_files_does_not_mutate_original_top_level(self) -> None: |
| 110 | file_bytes = b"contents" |
| 111 | original = {"file": file_bytes, "other": "value"} |
| 112 | |
| 113 | copied = deepcopy_with_paths(original, [["file"]]) |
| 114 | extracted = extract_files(copied, paths=[["file"]]) |
| 115 | |
| 116 | assert extracted == [("file", file_bytes)] |
| 117 | assert original == {"file": file_bytes, "other": "value"} |
| 118 | assert copied == {"other": "value"} |
| 119 | |
| 120 | def test_extract_files_does_not_mutate_original_nested_array_path(self) -> None: |
| 121 | file1 = b"f1" |
| 122 | file2 = b"f2" |
| 123 | original = { |
| 124 | "items": [ |
| 125 | {"file": file1, "extra": 1}, |
| 126 | {"file": file2, "extra": 2}, |
| 127 | ], |
| 128 | "title": "example", |
| 129 | } |
| 130 | |
| 131 | copied = deepcopy_with_paths(original, [["items", "<array>", "file"]]) |
| 132 | extracted = extract_files(copied, paths=[["items", "<array>", "file"]]) |
| 133 | |
| 134 | assert extracted == [("items[][file]", file1), ("items[][file]", file2)] |
| 135 | assert original == { |
| 136 | "items": [ |
| 137 | {"file": file1, "extra": 1}, |
| 138 | {"file": file2, "extra": 2}, |
| 139 | ], |
| 140 | "title": "example", |
| 141 | } |
| 142 | assert copied == { |
| 143 | "items": [ |
| 144 | {"extra": 1}, |
| 145 | {"extra": 2}, |
| 146 | ], |
| 147 | "title": "example", |
| 148 | } |
| 149 | |