xai-review 0.10.0__py3-none-any.whl → 0.11.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xai-review might be problematic. Click here for more details.
- ai_review/libs/json.py +6 -9
- ai_review/services/review/inline/service.py +2 -2
- ai_review/tests/suites/libs/test_json.py +2 -16
- ai_review/tests/suites/services/review/inline/test_service.py +6 -0
- {xai_review-0.10.0.dist-info → xai_review-0.11.0.dist-info}/METADATA +1 -1
- {xai_review-0.10.0.dist-info → xai_review-0.11.0.dist-info}/RECORD +10 -10
- {xai_review-0.10.0.dist-info → xai_review-0.11.0.dist-info}/WHEEL +0 -0
- {xai_review-0.10.0.dist-info → xai_review-0.11.0.dist-info}/entry_points.txt +0 -0
- {xai_review-0.10.0.dist-info → xai_review-0.11.0.dist-info}/licenses/LICENSE +0 -0
- {xai_review-0.10.0.dist-info → xai_review-0.11.0.dist-info}/top_level.txt +0 -0
ai_review/libs/json.py
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
3
|
CONTROL_CHARS_RE = re.compile(r"[\x00-\x1F]")
|
|
4
|
+
REPLACEMENTS = {
|
|
5
|
+
"\n": "\\n",
|
|
6
|
+
"\r": "\\r",
|
|
7
|
+
"\t": "\\t",
|
|
8
|
+
}
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
def sanitize_json_string(raw: str) -> str:
|
|
7
12
|
def replace(match: re.Match) -> str:
|
|
8
13
|
char = match.group()
|
|
9
|
-
|
|
10
|
-
case "\n":
|
|
11
|
-
return "\\n"
|
|
12
|
-
case "\r":
|
|
13
|
-
return "\\r"
|
|
14
|
-
case "\t":
|
|
15
|
-
return "\\t"
|
|
16
|
-
case _:
|
|
17
|
-
return f"\\u{ord(char):04x}"
|
|
14
|
+
return REPLACEMENTS.get(char, f"\\u{ord(char):04x}")
|
|
18
15
|
|
|
19
16
|
return CONTROL_CHARS_RE.sub(replace, raw)
|
|
@@ -18,12 +18,12 @@ class InlineCommentService:
|
|
|
18
18
|
try:
|
|
19
19
|
return InlineCommentListSchema.model_validate_json(raw)
|
|
20
20
|
except ValidationError as error:
|
|
21
|
-
logger.
|
|
21
|
+
logger.warning(f"Parse failed, trying sanitized JSON: {raw[:200]=}, {error=}")
|
|
22
22
|
try:
|
|
23
23
|
cleaned = sanitize_json_string(raw)
|
|
24
24
|
return InlineCommentListSchema.model_validate_json(cleaned)
|
|
25
25
|
except ValidationError as error:
|
|
26
|
-
logger.
|
|
26
|
+
logger.warning(f"Sanitized JSON still invalid: {raw[:200]=}, {error=}")
|
|
27
27
|
return None
|
|
28
28
|
|
|
29
29
|
@classmethod
|
|
@@ -12,30 +12,16 @@ from ai_review.libs.json import sanitize_json_string
|
|
|
12
12
|
("a\tb", "a\\tb"),
|
|
13
13
|
("abc\0def", "abc\\u0000def"),
|
|
14
14
|
("x\n\ry\t\0z", "x\\n\\ry\\t\\u0000z"),
|
|
15
|
+
("\n\r\t\0", "\\n\\r\\t\\u0000"),
|
|
16
|
+
("", "")
|
|
15
17
|
],
|
|
16
18
|
)
|
|
17
19
|
def test_sanitize_basic_cases(actual: str, expected: str) -> None:
|
|
18
20
|
assert sanitize_json_string(actual) == expected
|
|
19
21
|
|
|
20
22
|
|
|
21
|
-
def test_sanitize_multiple_control_chars() -> None:
|
|
22
|
-
raw = "A\nB\rC\tD\0E"
|
|
23
|
-
result = sanitize_json_string(raw)
|
|
24
|
-
assert result == "A\\nB\\rC\\tD\\u0000E"
|
|
25
|
-
|
|
26
|
-
|
|
27
23
|
def test_sanitize_idempotent() -> None:
|
|
28
24
|
raw = "foo\nbar"
|
|
29
25
|
once = sanitize_json_string(raw)
|
|
30
26
|
twice = sanitize_json_string(once)
|
|
31
27
|
assert once == twice
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def test_sanitize_empty_string() -> None:
|
|
35
|
-
assert sanitize_json_string("") == ""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def test_sanitize_only_control_chars() -> None:
|
|
39
|
-
raw = "\n\r\t\0"
|
|
40
|
-
result = sanitize_json_string(raw)
|
|
41
|
-
assert result == "\\n\\r\\t\\u0000"
|
|
@@ -53,6 +53,8 @@ def test_json_with_raw_newline_sanitized():
|
|
|
53
53
|
output = '[{"file": "e.py", "line": 3, "message": "line1\nline2"}]'
|
|
54
54
|
result = InlineCommentService.parse_model_output(output)
|
|
55
55
|
assert len(result.root) == 1
|
|
56
|
+
assert result.root[0].file == "e.py"
|
|
57
|
+
assert result.root[0].line == 3
|
|
56
58
|
assert result.root[0].message == "line1\nline2"
|
|
57
59
|
|
|
58
60
|
|
|
@@ -85,6 +87,8 @@ def test_try_parse_valid_json():
|
|
|
85
87
|
assert isinstance(result, InlineCommentListSchema)
|
|
86
88
|
assert len(result.root) == 1
|
|
87
89
|
assert result.root[0].file == "ok.py"
|
|
90
|
+
assert result.root[0].line == 1
|
|
91
|
+
assert result.root[0].message == "all good"
|
|
88
92
|
|
|
89
93
|
|
|
90
94
|
def test_try_parse_needs_sanitization():
|
|
@@ -92,6 +96,8 @@ def test_try_parse_needs_sanitization():
|
|
|
92
96
|
result = InlineCommentService.try_parse_model_output(raw)
|
|
93
97
|
assert result is not None
|
|
94
98
|
assert result.root[0].file == "bad.py"
|
|
99
|
+
assert result.root[0].line == 2
|
|
100
|
+
assert result.root[0].message == "line1\nline2"
|
|
95
101
|
assert "line1" in result.root[0].message
|
|
96
102
|
|
|
97
103
|
|
|
@@ -26,7 +26,7 @@ ai_review/clients/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
26
26
|
ai_review/clients/openai/client.py,sha256=N07ZRnbptOtab8imMUZbGL-kRoOwIZmNYbHySumD3IU,1707
|
|
27
27
|
ai_review/clients/openai/schema.py,sha256=glxwMtBrDA6W0BQgH-ruKe0bKH3Ps1P-Y1-2jGdqaUM,764
|
|
28
28
|
ai_review/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
-
ai_review/libs/json.py,sha256=
|
|
29
|
+
ai_review/libs/json.py,sha256=g-P5_pNUomQ-bGHCXASvPKj9Og0s9MaLFVEAkzqGp1A,350
|
|
30
30
|
ai_review/libs/logger.py,sha256=LbXR2Zk1btJ-83I-vHee7cUETgT1mHToSsqEI_8uM0U,370
|
|
31
31
|
ai_review/libs/resources.py,sha256=s9taAbL1Shl_GiGkPpkkivUcM1Yh6d_IQAG97gffsJU,748
|
|
32
32
|
ai_review/libs/asynchronous/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -103,7 +103,7 @@ ai_review/services/review/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
|
103
103
|
ai_review/services/review/service.py,sha256=8YhRFqhZAk2pAnkDaytKSCENlOeOti1brAJq3R9tVMY,8394
|
|
104
104
|
ai_review/services/review/inline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
105
105
|
ai_review/services/review/inline/schema.py,sha256=ry8sJdTgusQvFW51neRiapzgzVGwswwJzdYhaV3hbT0,1545
|
|
106
|
-
ai_review/services/review/inline/service.py,sha256=
|
|
106
|
+
ai_review/services/review/inline/service.py,sha256=34I3eK2Ra1l3aUvSYfO-Wx9aPfcgCWqTgjdoGHlNO08,2135
|
|
107
107
|
ai_review/services/review/policy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
108
108
|
ai_review/services/review/policy/service.py,sha256=yGDePLxAEF3N1Pkh47jGVd-4dGEESyxDXIXxV7KQfuY,2027
|
|
109
109
|
ai_review/services/review/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -131,7 +131,7 @@ ai_review/tests/suites/clients/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCe
|
|
|
131
131
|
ai_review/tests/suites/clients/openai/test_client.py,sha256=Ox5ifP1C_gSeDRacBa9DnXhe__Z8-WcbzR2JH_V3xKo,1050
|
|
132
132
|
ai_review/tests/suites/clients/openai/test_schema.py,sha256=x1tamS4GC9pOTpjieKDbK2D73CVV4BkATppytwMevLo,1599
|
|
133
133
|
ai_review/tests/suites/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
134
|
-
ai_review/tests/suites/libs/test_json.py,sha256=
|
|
134
|
+
ai_review/tests/suites/libs/test_json.py,sha256=q_tvFcL9EaN5jr48Ed_mxMEmW6xXS0xlZGqSooPZBa4,713
|
|
135
135
|
ai_review/tests/suites/libs/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
136
136
|
ai_review/tests/suites/libs/config/test_prompt.py,sha256=kDMTnykC54tTPfE6cqYRBbV8d5jzAKucXdJfwtqUybM,2242
|
|
137
137
|
ai_review/tests/suites/libs/diff/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -151,15 +151,15 @@ ai_review/tests/suites/services/prompt/test_service.py,sha256=M8vvBhEbyHnXCSiIRu
|
|
|
151
151
|
ai_review/tests/suites/services/review/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
152
152
|
ai_review/tests/suites/services/review/inline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
153
153
|
ai_review/tests/suites/services/review/inline/test_schema.py,sha256=tIz-1UA_GgwcdsyUqgrodiiVVmd_jhoOVmtEwzRVWiY,2474
|
|
154
|
-
ai_review/tests/suites/services/review/inline/test_service.py,sha256=
|
|
154
|
+
ai_review/tests/suites/services/review/inline/test_service.py,sha256=x8d-dhw_uEXtGVLDVv4xVodmscrXIfDkoAnG4UapdlQ,3815
|
|
155
155
|
ai_review/tests/suites/services/review/policy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
156
156
|
ai_review/tests/suites/services/review/policy/test_service.py,sha256=kRWT550OjWYQ7ZfsihBRc-tx-NMkhlynEsqur55RK0M,3687
|
|
157
157
|
ai_review/tests/suites/services/review/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
158
158
|
ai_review/tests/suites/services/review/summary/test_schema.py,sha256=xSoydvABZldHaVDa0OBFvYrj8wMuZqUDN3MO-XdvxOI,819
|
|
159
159
|
ai_review/tests/suites/services/review/summary/test_service.py,sha256=8UMvi_NL9frm280vD6Q1NCDrdI7K8YbXzoViIus-I2g,541
|
|
160
|
-
xai_review-0.
|
|
161
|
-
xai_review-0.
|
|
162
|
-
xai_review-0.
|
|
163
|
-
xai_review-0.
|
|
164
|
-
xai_review-0.
|
|
165
|
-
xai_review-0.
|
|
160
|
+
xai_review-0.11.0.dist-info/licenses/LICENSE,sha256=p-v8m7Kmz4KKc7PcvsGiGEmCw9AiSXY4_ylOPy_u--Y,11343
|
|
161
|
+
xai_review-0.11.0.dist-info/METADATA,sha256=HSYx4FRillzjL5CfB97QZZTxnCOlLRoRfDMg_Kufa4w,9618
|
|
162
|
+
xai_review-0.11.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
163
|
+
xai_review-0.11.0.dist-info/entry_points.txt,sha256=JyC5URanMi5io5P_PXQf7H_I1OGIpk5cZQhaPQ0g4Zs,53
|
|
164
|
+
xai_review-0.11.0.dist-info/top_level.txt,sha256=sTsZbfzLoqvRZKdKa-BcxWvjlHdrpbeJ6DrGY0EuR0E,10
|
|
165
|
+
xai_review-0.11.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|