-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathtest_error_handling.py
More file actions
187 lines (147 loc) · 6.63 KB
/
Copy pathtest_error_handling.py
File metadata and controls
187 lines (147 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
"""Tests for error handling controls."""
import json
import tempfile
import warnings
from pathlib import Path
import pytest
from iterable.exceptions import FormatParseError
from iterable.helpers.detect import open_iterable
class TestErrorPolicy:
"""Test error policy configuration."""
def test_error_policy_raise_default(self, tmp_path):
"""Test that 'raise' is the default error policy."""
# Create a CSV file with invalid data
csv_file = tmp_path / "test.csv"
csv_file.write_text("name,age\nJohn,30\nInvalid,row\nJane,25")
# Default behavior should raise
with open_iterable(str(csv_file)) as source:
rows = list(source)
# Should process valid rows
assert len(rows) >= 1
def test_error_policy_skip(self, tmp_path):
"""Test 'skip' error policy skips bad records."""
# Create a JSONL file with invalid JSON
jsonl_file = tmp_path / "test.jsonl"
jsonl_file.write_text('{"name": "John", "age": 30}\n{"invalid": json}\n{"name": "Jane", "age": 25}\n')
rows = []
with open_iterable(str(jsonl_file), iterableargs={"on_error": "skip"}) as source:
for row in source:
rows.append(row)
# Should have processed valid rows, skipped invalid
assert len(rows) >= 2
def test_error_policy_warn(self, tmp_path):
"""Test 'warn' error policy logs warnings."""
# Create a JSONL file with invalid JSON
jsonl_file = tmp_path / "test.jsonl"
jsonl_file.write_text('{"name": "John", "age": 30}\n{"invalid": json}\n')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
rows = []
with open_iterable(str(jsonl_file), iterableargs={"on_error": "warn"}) as source:
for row in source:
rows.append(row)
# Should have warnings
assert len(w) > 0
assert any("Parse error" in str(warning.message) for warning in w)
def test_error_policy_invalid(self):
"""Test that invalid error policy raises ValueError."""
with pytest.raises(ValueError, match="Invalid 'on_error' value"):
with open_iterable("dummy.csv", iterableargs={"on_error": "invalid"}):
pass
class TestErrorLogging:
"""Test error logging functionality."""
def test_error_log_file_path(self, tmp_path):
"""Test error logging to file path."""
# Create a JSONL file with invalid JSON
jsonl_file = tmp_path / "test.jsonl"
jsonl_file.write_text('{"name": "John"}\n{"invalid": json}\n')
error_log = tmp_path / "errors.log"
with open_iterable(
str(jsonl_file),
iterableargs={"on_error": "skip", "error_log": str(error_log)},
) as source:
list(source) # Process all rows
# Check that error log was created
assert error_log.exists()
# Check log content
with open(error_log) as f:
log_lines = f.readlines()
assert len(log_lines) > 0
# Parse first log entry
log_entry = json.loads(log_lines[0])
assert "timestamp" in log_entry
assert "filename" in log_entry
assert "error_type" in log_entry
assert "error_message" in log_entry
def test_error_log_file_object(self, tmp_path):
"""Test error logging to file-like object."""
# Create a JSONL file with invalid JSON
jsonl_file = tmp_path / "test.jsonl"
jsonl_file.write_text('{"invalid": json}\n')
error_log_file = tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".log")
error_log_path = error_log_file.name
error_log_file.close()
try:
with open(error_log_path, "w") as log_file:
with open_iterable(
str(jsonl_file),
iterableargs={"on_error": "skip", "error_log": log_file},
) as source:
list(source) # Process all rows
# Check that error log was written
with open(error_log_path) as f:
content = f.read()
assert len(content) > 0
finally:
Path(error_log_path).unlink()
class TestErrorContext:
"""Test contextual error information."""
def test_format_parse_error_context(self):
"""Test that FormatParseError includes contextual information."""
error = FormatParseError(
format_id="csv",
message="Invalid delimiter",
filename="test.csv",
row_number=5,
byte_offset=1234,
original_line="a,b,c",
)
assert error.filename == "test.csv"
assert error.row_number == 5
assert error.byte_offset == 1234
assert error.original_line == "a,b,c"
assert "test.csv" in str(error)
assert "row 5" in str(error) or "5" in str(error)
def test_error_context_in_jsonl(self, tmp_path):
"""Test that JSONL errors include context."""
jsonl_file = tmp_path / "test.jsonl"
jsonl_file.write_text('{"name": "John"}\n{"invalid": json}\n')
error_log = tmp_path / "errors.log"
with open_iterable(
str(jsonl_file),
iterableargs={"on_error": "skip", "error_log": str(error_log)},
) as source:
list(source)
# Check log has context
with open(error_log) as f:
log_entry = json.loads(f.readline())
assert "row_number" in log_entry
assert "original_line" in log_entry
assert log_entry["original_line"] == '{"invalid": json}'
class TestBackwardCompatibility:
"""Test that existing code continues to work."""
def test_default_behavior_unchanged(self, tmp_path):
"""Test that default behavior (raise) is unchanged."""
csv_file = tmp_path / "test.csv"
csv_file.write_text("name,age\nJohn,30\nJane,25")
# Should work exactly as before
with open_iterable(str(csv_file)) as source:
rows = list(source)
assert len(rows) == 2
def test_no_error_handling_args(self, tmp_path):
"""Test that code without error handling args works."""
jsonl_file = tmp_path / "test.jsonl"
jsonl_file.write_text('{"name": "John"}\n{"name": "Jane"}\n')
with open_iterable(str(jsonl_file)) as source:
rows = list(source)
assert len(rows) == 2