Skip to content

Commit 39143ca

Browse files
authored
Merge pull request #47 from sanders41/decorator
Added decorator to check for errors in status
2 parents 1485af3 + d05ad1d commit 39143ca

File tree

4 files changed

+190
-11
lines changed

4 files changed

+190
-11
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,25 @@ SearchResults(
291291
response = await index.update_documents_from_file_auto_batch("/path/to/file.json")
292292
```
293293

294+
* status_check decorator:
295+
296+
```py
297+
from meilisearch import Client
298+
from meilisearch_status_check_decorator import status_check
299+
300+
index = Client("http://localhost:7700", "masterKey").index("test")
301+
302+
@status_check(index=index)
303+
async def bad_insert():
304+
await index.add_documents(documents)
305+
```
306+
307+
If the adding of documents fails something similar to the folling will be printed:
308+
309+
```sh
310+
FAILED: [UpdateStatus(status='failed', update_id=0, update_type={'name': 'DocumentsAddition'}, enqueued_at=datetime.datetime(2021, 9, 2, 22, 47, 42, 234902, tzinfo=datetime.timezone.utc), duration=0.0, processed_at=datetime.datetime(2021, 9, 2, 22, 47, 42, 236647, tzinfo=datetime.timezone.utc), error=None)]
311+
```
312+
294313
## Compatibility with MeiliSearch
295314

296315
This package only guarantees the compatibility with [version v0.21.0 of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases/tag/v0.21.0).
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from __future__ import annotations
2+
3+
from asyncio import sleep
4+
from functools import wraps
5+
from typing import Any, Callable
6+
7+
from meilisearch_python_async.index import Index
8+
9+
10+
def status_check(index: Index) -> Callable:
11+
def decorator_status_check(func: Callable) -> Callable:
12+
@wraps(func)
13+
async def wrapper(*args: Any, **kwargs: Any) -> Any:
14+
initial_stats = await index.get_all_update_status()
15+
initial_status_count = 0 if not initial_stats else len(initial_stats)
16+
17+
result = await func(*args, **kwargs)
18+
19+
errors = False
20+
all_status = await index.get_all_update_status()
21+
22+
while True:
23+
if not all_status or not [
24+
x.status for x in all_status if x.status not in ["processed", "failed"]
25+
]:
26+
break
27+
28+
await sleep(1)
29+
all_status = await index.get_all_update_status()
30+
31+
if all_status:
32+
if len(all_status) == initial_status_count + 1:
33+
status = all_status[-1:]
34+
if status[0].status == "failed":
35+
errors = True
36+
else:
37+
status = all_status[initial_status_count:]
38+
for s in status:
39+
if s.status == "failed":
40+
errors = True
41+
42+
if errors:
43+
print(f"FAILED: {status}") # noqa: T001
44+
45+
return result
46+
47+
return wrapper
48+
49+
return decorator_status_check

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "meilisearch-python-async"
3-
version = "0.13.1"
3+
version = "0.14.0"
44
description = "A Python async client for the MeiliSearch API"
55
authors = ["Paul Sanders <[email protected]>"]
66
license = "MIT"

tests/integration/test_documents.py

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import pytest
55

6+
from meilisearch_python_async.decorators import status_check
67
from meilisearch_python_async.errors import MeiliSearchApiError, MeiliSearchError, PayloadTooLarge
78

89

@@ -24,6 +25,18 @@ def generate_test_movies(num_movies=50):
2425
return movies
2526

2627

28+
@pytest.fixture
29+
def add_document():
30+
return {
31+
"id": "1",
32+
"title": f"{'a' * 999999}",
33+
"poster": f"{'a' * 999999}",
34+
"overview": f"{'a' * 999999}",
35+
"release_date": 1551830399,
36+
"genre": f"{'a' * 999999}",
37+
}
38+
39+
2740
@pytest.mark.asyncio
2841
async def test_get_documents_default(empty_index):
2942
index = await empty_index()
@@ -43,16 +56,114 @@ async def test_add_documents(primary_key, expected_primary_key, empty_index, sma
4356
assert update.status == "processed"
4457

4558

46-
@pytest.fixture
47-
def add_document():
48-
return {
49-
"id": "1",
50-
"title": f"{'a' * 999999}",
51-
"poster": f"{'a' * 999999}",
52-
"overview": f"{'a' * 999999}",
53-
"release_date": 1551830399,
54-
"genre": f"{'a' * 999999}",
55-
}
59+
@pytest.mark.asyncio
60+
@pytest.mark.parametrize(
61+
"docs, expected_fail, expected_indexed",
62+
[
63+
(
64+
[
65+
{
66+
"id": 1,
67+
"name": "test 1",
68+
},
69+
{
70+
"id": 2,
71+
"name": "test 2",
72+
},
73+
],
74+
False,
75+
2,
76+
),
77+
(
78+
[
79+
{
80+
"name": "test 1",
81+
},
82+
{
83+
"name": "test 2",
84+
},
85+
],
86+
True,
87+
0,
88+
),
89+
],
90+
)
91+
async def test_status_check_decorator(docs, expected_fail, expected_indexed, empty_index, capfd):
92+
index = await empty_index()
93+
94+
@status_check(index=index)
95+
async def fn():
96+
await index.add_documents(docs)
97+
98+
await fn()
99+
stats = await index.get_stats()
100+
assert stats.number_of_documents == expected_indexed
101+
102+
out, _ = capfd.readouterr()
103+
104+
fail_text = "status='failed'"
105+
106+
if expected_fail:
107+
assert fail_text in out
108+
else:
109+
assert fail_text not in out
110+
111+
112+
@pytest.mark.asyncio
113+
@pytest.mark.parametrize(
114+
"docs, expected_fail, expected_indexed, expected_messages",
115+
[
116+
(
117+
[
118+
{
119+
"id": 1,
120+
"name": "test 1",
121+
},
122+
{
123+
"id": 2,
124+
"name": "test 2",
125+
},
126+
],
127+
False,
128+
2,
129+
0,
130+
),
131+
(
132+
[
133+
{
134+
"name": "test 1",
135+
},
136+
{
137+
"name": "test 2",
138+
},
139+
],
140+
True,
141+
0,
142+
2,
143+
),
144+
],
145+
)
146+
async def test_status_check_decorator_batch(
147+
docs, expected_fail, expected_indexed, expected_messages, empty_index, capfd
148+
):
149+
index = await empty_index()
150+
151+
@status_check(index=index)
152+
async def fn():
153+
await index.add_documents_in_batches(docs, batch_size=1)
154+
155+
await fn()
156+
stats = await index.get_stats()
157+
assert stats.number_of_documents == expected_indexed
158+
159+
out, _ = capfd.readouterr()
160+
161+
fail_text = "status='failed'"
162+
163+
if expected_fail:
164+
assert out.count(fail_text) == expected_messages
165+
else:
166+
assert fail_text not in out
56167

57168

58169
@pytest.mark.asyncio

0 commit comments

Comments
 (0)