Skip to content

Commit df74e09

Browse files
bors[bot]meili-botcurquizaalallema
authored
Merge #327
327: Changes related to the next MeiliSearch release (v0.23.0) r=alallema a=meili-bot Related to this issue: meilisearch/integration-guides#142 This PR: - gathers the changes related to the next MeiliSearch release (v0.23.0) so that this package is ready when the official release is out. - should pass the tests against the [latest pre-release of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases). - might eventually contain test failures until the MeiliSearch v0.23.0 is out. ⚠️ This PR should NOT be merged until the next release of MeiliSearch (v0.23.0) is out. _This PR is auto-generated for the [pre-release week](https://github.com/meilisearch/integration-guides/blob/master/guides/pre-release-week.md) purpose._ Done: - #329 - Add new methods: - `addDocumentsJson(string $documents, ?string $primaryKey = null)` - `addDocumentsNdJson(string $documents, ?string $primaryKey = null)` - `addDocumentsCsv(string $documents, ?string $primaryKey = null)` - Add tests for new methods - Remove json header `application/json` for every http methods - #331 Co-authored-by: meili-bot <[email protected]> Co-authored-by: Clémentine Urquizar <[email protected]> Co-authored-by: alallema <[email protected]> Co-authored-by: Amélie <[email protected]>
2 parents 4b3af92 + 7ab5bf0 commit df74e09

File tree

8 files changed

+954
-24
lines changed

8 files changed

+954
-24
lines changed

.code-samples.meilisearch.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,27 @@ search_parameter_guide_sort_1: |-
392392
client.index('books').search('science fiction', {
393393
'sort': ['price:asc']
394394
})
395+
geosearch_guide_filter_settings_1: |-
396+
client.index('restaurants').update_filterable_attributes([
397+
'_geo'
398+
])
399+
geosearch_guide_filter_usage_1: |-
400+
client.index('restaurants').search('', {
401+
'filter': '_geoRadius(45.4628328, 9.1076931, 2000)'
402+
})
403+
geosearch_guide_filter_usage_2: |-
404+
client.index('restaurants').search('', {
405+
'filter': '_geoRadius(45.4628328, 9.1076931, 2000) AND type = pizza'
406+
})
407+
geosearch_guide_sort_settings_1: |-
408+
client.index('restaurants').update_sortable_attributes([
409+
'_geo'
410+
])
411+
geosearch_guide_sort_usage_1: |-
412+
client.index('restaurants').search('', {
413+
'sort': ['_geoPoint(48.8583701,2.2922926):asc']
414+
})
415+
geosearch_guide_sort_usage_2: |-
416+
client.index('restaurants').search('', {
417+
'sort': ['_geoPoint(48.8583701,2.2922926):asc', 'rating:desc']
418+
})

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ JSON output:
151151

152152
## 🤖 Compatibility with MeiliSearch
153153

154-
This package only guarantees the compatibility with the [version v0.22.0 of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases/tag/v0.22.0).
154+
This package only guarantees the compatibility with the [version v0.23.0 of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases/tag/v0.23.0).
155155

156156
## 💡 Learn More
157157

datasets/songs.csv

Lines changed: 500 additions & 0 deletions
Large diffs are not rendered by default.

datasets/songs.ndjson

Lines changed: 225 additions & 0 deletions
Large diffs are not rendered by default.

meilisearch/_httprequests.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,33 @@ def __init__(self, config: Config) -> None:
1313
self.config = config
1414
self.headers = {
1515
'X-Meili-Api-Key': self.config.api_key,
16-
'Content-Type': 'application/json'
1716
}
1817

1918
def send_request(
2019
self,
2120
http_method: Callable,
2221
path: str,
23-
body: Optional[Union[Dict[str, Any], List[Dict[str, Any]], List[str]]] = None,
22+
body: Optional[Union[Dict[str, Any], List[Dict[str, Any]], List[str], str]] = None,
23+
content_type: Optional[str] = None,
2424
) -> Any:
25+
if content_type:
26+
self.headers['Content-Type'] = content_type
2527
try:
2628
request_path = self.config.url + '/' + path
27-
request = http_method(
28-
request_path,
29-
timeout=self.config.timeout,
30-
headers=self.headers,
31-
data=json.dumps(body) if body else "null"
32-
)
29+
if isinstance(body, bytes):
30+
request = http_method(
31+
request_path,
32+
timeout=self.config.timeout,
33+
headers=self.headers,
34+
data=body
35+
)
36+
else:
37+
request = http_method(
38+
request_path,
39+
timeout=self.config.timeout,
40+
headers=self.headers,
41+
data=json.dumps(body) if body else "null"
42+
)
3343
return self.__validate(request)
3444

3545
except requests.exceptions.Timeout as err:
@@ -45,16 +55,18 @@ def get(
4555
def post(
4656
self,
4757
path: str,
48-
body: Optional[Union[Dict[str, Any], List[Dict[str, Any]], List[str]]] = None,
58+
body: Optional[Union[Dict[str, Any], List[Dict[str, Any]], List[str], str]] = None,
59+
content_type: Optional[str] = 'application/json',
4960
) -> Any:
50-
return self.send_request(requests.post, path, body)
61+
return self.send_request(requests.post, path, body, content_type)
5162

5263
def put(
5364
self,
5465
path: str,
5566
body: Optional[Union[Dict[str, Any], List[Dict[str, Any]], List[str]]] = None,
67+
content_type: Optional[str] = 'application/json',
5668
) -> Any:
57-
return self.send_request(requests.put, path, body)
69+
return self.send_request(requests.put, path, body, content_type)
5870

5971
def delete(
6072
self,

meilisearch/index.py

Lines changed: 123 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,6 @@ def get_documents(self, parameters: Optional[Dict[str, Any]] = None) -> List[Dic
316316
"""
317317
if parameters is None:
318318
parameters = {}
319-
320319
return self.http.get(
321320
f'{self.config.paths.index}/{self.uid}/{self.config.paths.document}?{urllib.parse.urlencode(parameters)}'
322321
)
@@ -346,11 +345,7 @@ def add_documents(
346345
MeiliSearchApiError
347346
An error containing details about why MeiliSearch can't process your request. MeiliSearch error codes are described here: https://docs.meilisearch.com/errors/#meilisearch-errors
348347
"""
349-
if primary_key is None:
350-
url = f'{self.config.paths.index}/{self.uid}/{self.config.paths.document}'
351-
else:
352-
primary_key = urllib.parse.urlencode({'primaryKey': primary_key})
353-
url = f'{self.config.paths.index}/{self.uid}/{self.config.paths.document}?{primary_key}'
348+
url = self._build_url(primary_key)
354349
return self.http.post(url, documents)
355350

356351
def add_documents_in_batches(
@@ -391,6 +386,118 @@ def add_documents_in_batches(
391386

392387
return update_ids
393388

389+
def add_documents_json(
390+
self,
391+
str_documents: str,
392+
primary_key: Optional[str] = None,
393+
) -> Dict[str, int]:
394+
"""Add string documents from JSON file to the index.
395+
396+
Parameters
397+
----------
398+
str_documents:
399+
String of document from a JSON file.
400+
primary_key (optional):
401+
The primary-key used in index. Ignored if already set up.
402+
403+
Returns
404+
-------
405+
update:
406+
Dictionary containing an update id to track the action:
407+
https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status
408+
409+
Raises
410+
------
411+
MeiliSearchApiError
412+
An error containing details about why MeiliSearch can't process your request. MeiliSearch error codes are described here: https://docs.meilisearch.com/errors/#meilisearch-errors
413+
"""
414+
return self.add_documents_raw(str_documents, primary_key, 'application/json')
415+
416+
def add_documents_csv(
417+
self,
418+
str_documents: str,
419+
primary_key: Optional[str] = None,
420+
) -> Dict[str, int]:
421+
"""Add string documents from a CSV file to the index.
422+
423+
Parameters
424+
----------
425+
str_documents:
426+
String of document from a CSV file.
427+
primary_key (optional):
428+
The primary-key used in index. Ignored if already set up.
429+
430+
Returns
431+
-------
432+
update:
433+
Dictionary containing an update id to track the action:
434+
https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status
435+
436+
Raises
437+
------
438+
MeiliSearchApiError
439+
An error containing details about why MeiliSearch can't process your request. MeiliSearch error codes are described here: https://docs.meilisearch.com/errors/#meilisearch-errors
440+
"""
441+
return self.add_documents_raw(str_documents, primary_key, 'text/csv')
442+
443+
def add_documents_ndjson(
444+
self,
445+
str_documents: str,
446+
primary_key: Optional[str] = None,
447+
) -> Dict[str, int]:
448+
"""Add string documents from a NDJSON file to the index.
449+
450+
Parameters
451+
----------
452+
str_documents:
453+
String of document from a NDJSON file.
454+
primary_key (optional):
455+
The primary-key used in index. Ignored if already set up.
456+
457+
Returns
458+
-------
459+
update:
460+
Dictionary containing an update id to track the action:
461+
https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status
462+
463+
Raises
464+
------
465+
MeiliSearchApiError
466+
An error containing details about why MeiliSearch can't process your request. MeiliSearch error codes are described here: https://docs.meilisearch.com/errors/#meilisearch-errors
467+
"""
468+
return self.add_documents_raw(str_documents, primary_key, 'application/x-ndjson')
469+
470+
def add_documents_raw(
471+
self,
472+
str_documents: str,
473+
primary_key: Optional[str] = None,
474+
content_type: Optional[str] = None,
475+
) -> Dict[str, int]:
476+
"""Add string documents to the index.
477+
478+
Parameters
479+
----------
480+
str_documents:
481+
String of document.
482+
primary_key (optional):
483+
The primary-key used in index. Ignored if already set up.
484+
type:
485+
The type of document. Type available: 'csv', 'json', 'jsonl'
486+
487+
Returns
488+
-------
489+
update:
490+
Dictionary containing an update id to track the action:
491+
https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status
492+
493+
Raises
494+
------
495+
MeiliSearchApiError
496+
An error containing details about why MeiliSearch can't process your request. MeiliSearch error codes are described here: https://docs.meilisearch.com/errors/#meilisearch-errors
497+
"""
498+
url = self._build_url(primary_key)
499+
return self.http.post(url, str_documents, content_type)
500+
394501
def update_documents(
395502
self,
396503
documents: List[Dict[str, Any]],
@@ -416,11 +523,7 @@ def update_documents(
416523
MeiliSearchApiError
417524
An error containing details about why MeiliSearch can't process your request. MeiliSearch error codes are described here: https://docs.meilisearch.com/errors/#meilisearch-errors
418525
"""
419-
if primary_key is None:
420-
url = f'{self.config.paths.index}/{self.uid}/{self.config.paths.document}'
421-
else:
422-
primary_key = urllib.parse.urlencode({'primaryKey': primary_key})
423-
url = f'{self.config.paths.index}/{self.uid}/{self.config.paths.document}?{primary_key}'
526+
url = self._build_url(primary_key)
424527
return self.http.put(url, documents)
425528

426529
def update_documents_in_batches(
@@ -1134,3 +1237,12 @@ def _iso_to_date_time(iso_date: Optional[Union[datetime, str]]) -> Optional[date
11341237

11351238
def __settings_url_for(self, sub_route: str) -> str:
11361239
return f'{self.config.paths.index}/{self.uid}/{self.config.paths.setting}/{sub_route}'
1240+
1241+
def _build_url(
1242+
self,
1243+
primary_key: Optional[str] = None,
1244+
) -> str:
1245+
if primary_key is None:
1246+
return f'{self.config.paths.index}/{self.uid}/{self.config.paths.document}'
1247+
primary_key = urllib.parse.urlencode({'primaryKey': primary_key})
1248+
return f'{self.config.paths.index}/{self.uid}/{self.config.paths.document}?{primary_key}'

meilisearch/tests/conftest.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,33 @@ def small_movies():
3535
"""
3636
Runs once per session. Provides the content of small_movies.json.
3737
"""
38-
with open('./datasets/small_movies.json', 'r', encoding="utf8") as movie_file:
38+
with open('./datasets/small_movies.json', 'r', encoding='utf-8') as movie_file:
3939
yield json.loads(movie_file.read())
4040

41+
@fixture(scope='session')
42+
def small_movies_json_file():
43+
"""
44+
Runs once per session. Provides the content of small_movies.json from read.
45+
"""
46+
with open('./datasets/small_movies.json', 'r', encoding='utf-8') as movie_json_file:
47+
return movie_json_file.read().encode('utf-8')
48+
49+
@fixture(scope='session')
50+
def songs_csv():
51+
"""
52+
Runs once per session. Provides the content of songs.csv from read..
53+
"""
54+
with open('./datasets/songs.csv', 'r', encoding='utf-8') as song_csv_file:
55+
return song_csv_file.read().encode('utf-8')
56+
57+
@fixture(scope='session')
58+
def songs_ndjson():
59+
"""
60+
Runs once per session. Provides the content of songs.ndjson from read..
61+
"""
62+
with open('./datasets/songs.ndjson', 'r', encoding='utf-8') as song_ndjson_file:
63+
return song_ndjson_file.read().encode('utf-8')
64+
4165
@fixture(scope='function')
4266
def empty_index(client):
4367
def index_maker(index_name=common.INDEX_UID):

meilisearch/tests/index/test_index_document_meilisearch.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,36 @@ def test_delete_all_documents(index_with_documents):
144144
response = index.get_documents()
145145
assert isinstance(response, list)
146146
assert response == []
147+
148+
def test_add_documents_csv(empty_index, songs_csv):
149+
"""Tests adding new documents to a clean index."""
150+
index = empty_index()
151+
response = index.add_documents_csv(songs_csv)
152+
assert isinstance(response, dict)
153+
assert 'updateId' in response
154+
update = index.wait_for_pending_update(response['updateId'])
155+
assert update['status'] == 'processed'
156+
assert update['type']['number'] != 0
157+
assert index.get_primary_key() == 'id'
158+
159+
def test_add_documents_json(empty_index, small_movies_json_file):
160+
"""Tests adding new documents to a clean index."""
161+
index = empty_index()
162+
response = index.add_documents_json(small_movies_json_file)
163+
assert isinstance(response, dict)
164+
assert 'updateId' in response
165+
update = index.wait_for_pending_update(response['updateId'])
166+
assert update['status'] == 'processed'
167+
assert update['type']['number'] != 0
168+
assert index.get_primary_key() == 'id'
169+
170+
def test_add_documents_ndjson(empty_index, songs_ndjson):
171+
"""Tests adding new documents to a clean index."""
172+
index = empty_index()
173+
response = index.add_documents_ndjson(songs_ndjson)
174+
assert isinstance(response, dict)
175+
assert 'updateId' in response
176+
update = index.wait_for_pending_update(response['updateId'])
177+
assert update['status'] == 'processed'
178+
assert update['type']['number'] != 0
179+
assert index.get_primary_key() == 'id'

0 commit comments

Comments
 (0)