xai-review 0.32.0__py3-none-any.whl → 0.33.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.

@@ -1,8 +1,8 @@
1
1
  import hashlib
2
- from datetime import datetime
2
+ from datetime import datetime, timezone
3
3
 
4
4
 
5
5
  def make_artifact_id(text: str) -> str:
6
6
  sha = hashlib.sha1(text.encode()).hexdigest()[:8]
7
- ts = datetime.utcnow().strftime("%Y.%m.%d_%H-%M-%S")
7
+ ts = datetime.now(timezone.utc).strftime("%Y.%m.%d_%H-%M-%S")
8
8
  return f"{ts}_{sha}"
@@ -2,6 +2,7 @@ from pathlib import Path
2
2
 
3
3
  import pytest
4
4
 
5
+ from ai_review.services.artifacts.service import ArtifactsService
5
6
  from ai_review.services.artifacts.types import ArtifactsServiceProtocol
6
7
 
7
8
 
@@ -49,3 +50,8 @@ class FakeArtifactsService(ArtifactsServiceProtocol):
49
50
  @pytest.fixture
50
51
  def fake_artifacts_service() -> FakeArtifactsService:
51
52
  return FakeArtifactsService()
53
+
54
+
55
+ @pytest.fixture
56
+ def artifacts_service() -> ArtifactsService:
57
+ return ArtifactsService()
File without changes
@@ -0,0 +1,92 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ import aiofiles
5
+ import pytest
6
+
7
+ from ai_review.config import settings
8
+ from ai_review.libs.config.artifacts import ArtifactsConfig
9
+ from ai_review.services.artifacts.service import ArtifactsService
10
+
11
+
12
+ @pytest.mark.asyncio
13
+ async def test_save_llm_interaction_creates_file(
14
+ tmp_path: Path,
15
+ monkeypatch: pytest.MonkeyPatch,
16
+ artifacts_service: ArtifactsService
17
+ ):
18
+ """Checks that a JSON file is created with the correct name and content when LLM saving is enabled."""
19
+ monkeypatch.setattr(settings, "artifacts", ArtifactsConfig(llm_dir=tmp_path, llm_enabled=True))
20
+
21
+ artifact_id = await artifacts_service.save_llm_interaction(
22
+ prompt="Hello world",
23
+ prompt_system="system prompt",
24
+ response="model answer"
25
+ )
26
+
27
+ assert artifact_id is not None
28
+ artifact_path = tmp_path / f"{artifact_id}.json"
29
+ assert artifact_path.exists(), "Artifact file was not created"
30
+
31
+ async with aiofiles.open(artifact_path, "r", encoding="utf-8") as file:
32
+ content = await file.read()
33
+ data = json.loads(content)
34
+ assert data["id"] == artifact_id
35
+ assert data["prompt"] == "Hello world"
36
+ assert data["response"] == "model answer"
37
+ assert data["prompt_system"] == "system prompt"
38
+
39
+
40
+ @pytest.mark.asyncio
41
+ async def test_save_llm_interaction_disabled(
42
+ monkeypatch: pytest.MonkeyPatch,
43
+ artifacts_service: ArtifactsService
44
+ ):
45
+ """Checks that the method returns None and does not create a file if LLM saving is disabled."""
46
+ monkeypatch.setattr(settings, "artifacts", ArtifactsConfig(llm_enabled=False))
47
+
48
+ artifact_id = await artifacts_service.save_llm_interaction(
49
+ prompt="ignored",
50
+ prompt_system="ignored",
51
+ response="ignored"
52
+ )
53
+
54
+ assert artifact_id is None
55
+
56
+
57
+ @pytest.mark.asyncio
58
+ async def test_save_artifact_writes_file(tmp_path: Path, artifacts_service: ArtifactsService):
59
+ """Checks that save_artifact writes content to the given file path."""
60
+ file_path = tmp_path / "test.json"
61
+ content = '{"key": "value"}'
62
+
63
+ result = await artifacts_service.save_artifact(file=file_path, content=content, kind="test")
64
+
65
+ assert result == file_path
66
+ assert file_path.exists()
67
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as f:
68
+ saved_content = await f.read()
69
+ assert saved_content == content
70
+
71
+
72
+ @pytest.mark.asyncio
73
+ async def test_save_artifact_handles_exception(
74
+ monkeypatch: pytest.MonkeyPatch,
75
+ artifacts_service: ArtifactsService
76
+ ):
77
+ """Checks that save_artifact gracefully returns None on write error."""
78
+
79
+ class BrokenAsyncFile:
80
+ async def __aenter__(self):
81
+ raise OSError("disk full")
82
+
83
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
84
+ return False
85
+
86
+ monkeypatch.setattr(
87
+ "ai_review.services.artifacts.service.aiofiles.open",
88
+ lambda *args, **kwargs: BrokenAsyncFile()
89
+ )
90
+
91
+ result = await artifacts_service.save_artifact(Path("/fake/path.json"), "data")
92
+ assert result is None
@@ -0,0 +1,28 @@
1
+ import hashlib
2
+ import re
3
+
4
+ import pytest
5
+
6
+ from ai_review.services.artifacts.tools import make_artifact_id
7
+
8
+
9
+ @pytest.mark.parametrize("text", ["hello", "some longer text", ""])
10
+ def test_make_artifact_id_format_and_sha(text: str):
11
+ """Checks that the function returns a valid artifact ID format and correct SHA prefix."""
12
+ artifact_id = make_artifact_id(text)
13
+
14
+ pattern = r"^\d{4}\.\d{2}\.\d{2}_\d{2}-\d{2}-\d{2}_[0-9a-f]{8}$"
15
+ assert re.match(pattern, artifact_id), f"Invalid format: {artifact_id}"
16
+
17
+ expected_sha = hashlib.sha1(text.encode()).hexdigest()[:8]
18
+ assert artifact_id.endswith(expected_sha)
19
+
20
+
21
+ def test_make_artifact_id_is_deterministic_for_same_input():
22
+ """Checks that the SHA part is deterministic (identical for the same input)."""
23
+ sha1 = hashlib.sha1("repeatable".encode()).hexdigest()[:8]
24
+ artifact_id1 = make_artifact_id("repeatable")
25
+ artifact_id2 = make_artifact_id("repeatable")
26
+
27
+ assert artifact_id1.split("_")[2] == sha1
28
+ assert artifact_id2.split("_")[2] == sha1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xai-review
3
- Version: 0.32.0
3
+ Version: 0.33.0
4
4
  Summary: AI-powered code review tool
5
5
  Author-email: Nikita Filonov <nikita.filonov@example.com>
6
6
  Maintainer-email: Nikita Filonov <nikita.filonov@example.com>
@@ -220,7 +220,7 @@ jobs:
220
220
  with:
221
221
  fetch-depth: 0
222
222
 
223
- - uses: Nikita-Filonov/ai-review@v0.32.0
223
+ - uses: Nikita-Filonov/ai-review@v0.33.0
224
224
  with:
225
225
  review-command: ${{ inputs.review-command }}
226
226
  env:
@@ -137,7 +137,7 @@ ai_review/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
137
137
  ai_review/services/artifacts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
138
  ai_review/services/artifacts/schema.py,sha256=o4dqG5LFCdAQY3wjRF5rImANe-X20g4zX_bCIKiHLSk,291
139
139
  ai_review/services/artifacts/service.py,sha256=SDHwYm9I4pSPISyNWqHEOR-wTTEa5ThsIi458C9hBt8,1789
140
- ai_review/services/artifacts/tools.py,sha256=_ZVNwyhZDiGlPAtIgLzb7TF1zBGJy8Hq32H3xoGvOkQ,223
140
+ ai_review/services/artifacts/tools.py,sha256=KrCQxbBEBIgqUhxZwCmbj1f07B5403gkfSgpS9qLpE4,242
141
141
  ai_review/services/artifacts/types.py,sha256=VPEDuQQciyQL8qcmgFuZxZUuuh2-xLwqwxmNZr62F3E,448
142
142
  ai_review/services/cost/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
143
  ai_review/services/cost/schema.py,sha256=K3uCIMMxGL8AaIPh4a-d0mT5uIJuk3f805DkP8o8DtY,1323
@@ -237,7 +237,7 @@ ai_review/tests/fixtures/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
237
237
  ai_review/tests/fixtures/libs/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
238
238
  ai_review/tests/fixtures/libs/llm/output_json_parser.py,sha256=Eu0tCK5cD1d9X1829ruahih7jQoehGozIEugS71AAA8,275
239
239
  ai_review/tests/fixtures/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
240
- ai_review/tests/fixtures/services/artifacts.py,sha256=V5FvUnC9OAo0n-paxxJP5OxAgLz1Zz3OZ8zZvqu_01w,1462
240
+ ai_review/tests/fixtures/services/artifacts.py,sha256=ETxcGT27YUSegSjxKuuXx1B8ZCXmAm0hhUzW5Vqt7Os,1621
241
241
  ai_review/tests/fixtures/services/cost.py,sha256=A6Ja0CtQ-k6pR2-B5LRE8EzkqPL34xHGXYtaILjhYvw,1612
242
242
  ai_review/tests/fixtures/services/diff.py,sha256=rOLFR-giYJlE2qUYTOT9BxyJhQ-fbXDdYCw3zed4-9M,1471
243
243
  ai_review/tests/fixtures/services/git.py,sha256=zDNNLZDoVC7r4LuF1N1MUgzhcAl2nhDdFC9olpR_PjQ,1441
@@ -308,6 +308,9 @@ ai_review/tests/suites/libs/llm/test_output_json_parser.py,sha256=2KwnXZc3dlUWM1
308
308
  ai_review/tests/suites/libs/template/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
309
309
  ai_review/tests/suites/libs/template/test_render.py,sha256=n-ss5bd_hwc-RzYmqWmFM6KSlP1zLSnlsW1Yki12Bpw,1890
310
310
  ai_review/tests/suites/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
311
+ ai_review/tests/suites/services/artifacts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
312
+ ai_review/tests/suites/services/artifacts/test_service.py,sha256=OFYHORgvKVLXrAWImTUs9nXAuAUGUVQT-QBZPU3WjVc,3054
313
+ ai_review/tests/suites/services/artifacts/test_tools.py,sha256=kvxGoCcL6JovW10GoVycKE5M3e-fkbVd6OpHLbPvhIA,1022
311
314
  ai_review/tests/suites/services/cost/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
312
315
  ai_review/tests/suites/services/cost/test_schema.py,sha256=AI3Wg1sR6nzLpkEqJGDu6nDYwiwzbbghsxhRNwRsUFA,3044
313
316
  ai_review/tests/suites/services/cost/test_service.py,sha256=9_Mi5hu2cq3w2tIEPfhrn9x8SblCT5m1W-QUOc9BZds,3258
@@ -373,9 +376,9 @@ ai_review/tests/suites/services/vcs/github/test_client.py,sha256=mNt1bA6aVU3REsJ
373
376
  ai_review/tests/suites/services/vcs/gitlab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
374
377
  ai_review/tests/suites/services/vcs/gitlab/test_adapter.py,sha256=BYBP2g1AKF_jCSJYJj16pW7M_6PprwD9reYEpdw3StU,4340
375
378
  ai_review/tests/suites/services/vcs/gitlab/test_client.py,sha256=dnI-YxYADmVF2GS9rp6-JPkcqsn4sN8Fjbe4MkeYMaE,8476
376
- xai_review-0.32.0.dist-info/licenses/LICENSE,sha256=p-v8m7Kmz4KKc7PcvsGiGEmCw9AiSXY4_ylOPy_u--Y,11343
377
- xai_review-0.32.0.dist-info/METADATA,sha256=zRXQ50EMX8ekmcWLN4F5E5jnNxVS-62t9zbiY9FqKus,12689
378
- xai_review-0.32.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
379
- xai_review-0.32.0.dist-info/entry_points.txt,sha256=JyC5URanMi5io5P_PXQf7H_I1OGIpk5cZQhaPQ0g4Zs,53
380
- xai_review-0.32.0.dist-info/top_level.txt,sha256=sTsZbfzLoqvRZKdKa-BcxWvjlHdrpbeJ6DrGY0EuR0E,10
381
- xai_review-0.32.0.dist-info/RECORD,,
379
+ xai_review-0.33.0.dist-info/licenses/LICENSE,sha256=p-v8m7Kmz4KKc7PcvsGiGEmCw9AiSXY4_ylOPy_u--Y,11343
380
+ xai_review-0.33.0.dist-info/METADATA,sha256=olP2J_qC--KQKEyDvq1JNIUtqgd029Lli6fiI6zKAc0,12689
381
+ xai_review-0.33.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
382
+ xai_review-0.33.0.dist-info/entry_points.txt,sha256=JyC5URanMi5io5P_PXQf7H_I1OGIpk5cZQhaPQ0g4Zs,53
383
+ xai_review-0.33.0.dist-info/top_level.txt,sha256=sTsZbfzLoqvRZKdKa-BcxWvjlHdrpbeJ6DrGY0EuR0E,10
384
+ xai_review-0.33.0.dist-info/RECORD,,