chore: import upstream snapshot with attribution
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
"""
|
||||
Tests for edge cases in JSON extraction functionality.
|
||||
"""
|
||||
|
||||
import json
|
||||
import pytest
|
||||
|
||||
from instructor.utils import (
|
||||
extract_json_from_codeblock,
|
||||
extract_json_from_stream,
|
||||
)
|
||||
|
||||
|
||||
class TestJSONExtractionEdgeCases:
|
||||
"""Test edge cases for the JSON extraction utilities."""
|
||||
|
||||
def test_empty_input(self):
|
||||
"""Test extraction from empty input."""
|
||||
result = extract_json_from_codeblock("")
|
||||
assert result == ""
|
||||
|
||||
def test_no_json_content(self):
|
||||
"""Test extraction when no JSON-like content is present."""
|
||||
text = "This is just plain text with no JSON content."
|
||||
result = extract_json_from_codeblock(text)
|
||||
assert "{" not in result
|
||||
assert result == text
|
||||
|
||||
def test_multiple_json_objects(self):
|
||||
"""Test extraction when multiple JSON objects are present."""
|
||||
text = """
|
||||
First object: {"name": "First", "id": 1}
|
||||
Second object: {"name": "Second", "id": 2}
|
||||
"""
|
||||
# With our regex pattern, it might extract both objects
|
||||
# The main point is that it should extract valid JSON
|
||||
result = extract_json_from_codeblock(text)
|
||||
|
||||
# Clean up the result for this test case
|
||||
if "Second object" in result:
|
||||
# If it extracted too much, manually fix it
|
||||
result = result[: result.find("Second object")].strip()
|
||||
|
||||
parsed = json.loads(result)
|
||||
assert "name" in parsed
|
||||
assert "id" in parsed
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"text, expected",
|
||||
[
|
||||
(
|
||||
"""
|
||||
```json
|
||||
{
|
||||
"message": "He said, \\"Hello world\\""
|
||||
}
|
||||
```
|
||||
""",
|
||||
{"message": 'He said, "Hello world"'},
|
||||
),
|
||||
(
|
||||
"""
|
||||
{
|
||||
"greeting": "こんにちは",
|
||||
"emoji": "😀"
|
||||
}
|
||||
""",
|
||||
{"greeting": "こんにちは", "emoji": "😀"},
|
||||
),
|
||||
(
|
||||
r"""
|
||||
{
|
||||
"path": "C:\\Users\\test\\documents",
|
||||
"regex": "\\d+"
|
||||
}
|
||||
""",
|
||||
{"path": r"C:\Users\test\documents", "regex": r"\d+"},
|
||||
),
|
||||
(
|
||||
"""
|
||||
Outer start
|
||||
```
|
||||
Inner start
|
||||
```json
|
||||
{"level": "inner"}
|
||||
```
|
||||
Inner end
|
||||
```
|
||||
Outer end
|
||||
""",
|
||||
{"level": "inner"},
|
||||
),
|
||||
(
|
||||
"""
|
||||
```json
|
||||
{"name": "```string value with a codeblock```"}
|
||||
```
|
||||
""",
|
||||
{"name": "```string value with a codeblock```"},
|
||||
),
|
||||
(
|
||||
"""
|
||||
Malformed start
|
||||
``json
|
||||
{"status": "malformed"}
|
||||
``
|
||||
End
|
||||
""",
|
||||
{"status": "malformed"},
|
||||
),
|
||||
(
|
||||
"""
|
||||
```json
|
||||
{
|
||||
"level1": {
|
||||
"level2": {
|
||||
"level3": {
|
||||
"level4": {
|
||||
"value": "deep"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"array": [
|
||||
{"item": 1},
|
||||
{"item": 2, "nested": [3, 4, [5, 6]]}
|
||||
]
|
||||
}
|
||||
```
|
||||
""",
|
||||
{
|
||||
"level1": {"level2": {"level3": {"level4": {"value": "deep"}}}},
|
||||
"array": [
|
||||
{"item": 1},
|
||||
{"item": 2, "nested": [3, 4, [5, 6]]},
|
||||
],
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_codeblock_parsing_variants(self, text, expected):
|
||||
"""Test extraction with common codeblock parsing variants."""
|
||||
result = extract_json_from_codeblock(text)
|
||||
parsed = json.loads(result)
|
||||
assert parsed == expected
|
||||
|
||||
def test_json_with_comments(self):
|
||||
"""Test extraction of JSON that has comments (invalid JSON)."""
|
||||
text = """
|
||||
```
|
||||
{
|
||||
"name": "Test", // This is a comment
|
||||
"description": "Testing with comments"
|
||||
/*
|
||||
Multi-line comment
|
||||
*/
|
||||
}
|
||||
```
|
||||
"""
|
||||
result = extract_json_from_codeblock(text)
|
||||
# Comments would make this invalid JSON
|
||||
with pytest.raises(json.JSONDecodeError):
|
||||
json.loads(result)
|
||||
# But we should still extract the content between braces
|
||||
assert "Test" in result and "comments" in result
|
||||
|
||||
def test_stream_with_nested_braces(self):
|
||||
"""Test stream extraction with nested braces."""
|
||||
chunks = [
|
||||
'{"outer": {',
|
||||
'"inner1": {"a": 1},',
|
||||
'"inner2": {',
|
||||
'"b": 2, "c": {"d": 3}',
|
||||
"}",
|
||||
"}}",
|
||||
]
|
||||
|
||||
collected = "".join(extract_json_from_stream(chunks))
|
||||
parsed = json.loads(collected)
|
||||
|
||||
assert parsed["outer"]["inner1"]["a"] == 1
|
||||
assert parsed["outer"]["inner2"]["c"]["d"] == 3
|
||||
|
||||
def test_stream_with_string_containing_braces(self):
|
||||
"""Test stream extraction with strings containing brace characters."""
|
||||
chunks = [
|
||||
'{"text": "This string {contains} braces",',
|
||||
'"code": "function() { return true; }",',
|
||||
'"valid": true}',
|
||||
]
|
||||
|
||||
collected = "".join(extract_json_from_stream(chunks))
|
||||
parsed = json.loads(collected)
|
||||
|
||||
assert parsed["text"] == "This string {contains} braces"
|
||||
assert parsed["code"] == "function() { return true; }"
|
||||
assert parsed["valid"] is True
|
||||
Reference in New Issue
Block a user