|
| 1 | +""" |
| 2 | +Module for interacting with the stemming dictionaries endpoint of the Typesense API (async). |
| 3 | +
|
| 4 | +This module provides a class for managing stemming dictionaries in Typesense, including creating |
| 5 | +and updating them asynchronously. |
| 6 | +
|
| 7 | +Classes: |
| 8 | + - AsyncStemmingDictionaries: Handles async operations related to stemming dictionaries. |
| 9 | +
|
| 10 | +Methods: |
| 11 | + - __init__: Initializes the AsyncStemmingDictionaries object. |
| 12 | + - __getitem__: Retrieves or creates an AsyncStemmingDictionary object for a given dictionary_id. |
| 13 | + - upsert: Creates or updates a stemming dictionary. |
| 14 | + - _upsert_list: Creates or updates a list of stemming dictionaries. |
| 15 | + - _dump_to_jsonl: Dumps a list of StemmingDictionaryCreateSchema objects to a JSONL string. |
| 16 | + - _parse_response: Parses the response from the upsert operation. |
| 17 | + - _upsert_raw: Performs the raw upsert operation. |
| 18 | + - _endpoint_path: Constructs the API endpoint path for this specific stemming dictionary. |
| 19 | +
|
| 20 | +The AsyncStemmingDictionaries class interacts with the Typesense API to manage stemming dictionary |
| 21 | +operations. It provides methods to create, update, and retrieve stemming dictionaries, as well as |
| 22 | +access individual AsyncStemmingDictionary objects. |
| 23 | +
|
| 24 | +For more information on stemming dictionaries, |
| 25 | +refer to the Stemming [documentation](https://typesense.org/docs/28.0/api/stemming.html) |
| 26 | +""" |
| 27 | + |
| 28 | +import json |
| 29 | +import sys |
| 30 | + |
| 31 | +if sys.version_info >= (3, 11): |
| 32 | + import typing |
| 33 | +else: |
| 34 | + import typing_extensions as typing |
| 35 | + |
| 36 | +from typesense.async_api_call import AsyncApiCall |
| 37 | +from typesense.async_stemming_dictionary import AsyncStemmingDictionary |
| 38 | +from typesense.types.stemming import ( |
| 39 | + StemmingDictionariesRetrieveSchema, |
| 40 | + StemmingDictionaryCreateSchema, |
| 41 | +) |
| 42 | + |
| 43 | + |
| 44 | +class AsyncStemmingDictionaries: |
| 45 | + """ |
| 46 | + Class for managing stemming dictionaries in Typesense (async). |
| 47 | +
|
| 48 | + This class provides methods to interact with stemming dictionaries, including |
| 49 | + creating, updating, and retrieving them. |
| 50 | +
|
| 51 | + Attributes: |
| 52 | + api_call (AsyncApiCall): The API call object for making requests. |
| 53 | + stemming_dictionaries (Dict[str, AsyncStemmingDictionary]): A dictionary of |
| 54 | + AsyncStemmingDictionary objects. |
| 55 | + """ |
| 56 | + |
| 57 | + resource_path: typing.Final[str] = "/stemming/dictionaries" |
| 58 | + |
| 59 | + def __init__(self, api_call: AsyncApiCall): |
| 60 | + """ |
| 61 | + Initialize the AsyncStemmingDictionaries object. |
| 62 | +
|
| 63 | + Args: |
| 64 | + api_call (AsyncApiCall): The API call object for making requests. |
| 65 | + """ |
| 66 | + self.api_call = api_call |
| 67 | + self.stemming_dictionaries: typing.Dict[str, AsyncStemmingDictionary] = {} |
| 68 | + |
| 69 | + def __getitem__(self, dictionary_id: str) -> AsyncStemmingDictionary: |
| 70 | + """ |
| 71 | + Get or create an AsyncStemmingDictionary object for a given dictionary_id. |
| 72 | +
|
| 73 | + Args: |
| 74 | + dictionary_id (str): The ID of the stemming dictionary. |
| 75 | +
|
| 76 | + Returns: |
| 77 | + AsyncStemmingDictionary: The AsyncStemmingDictionary object for the given ID. |
| 78 | + """ |
| 79 | + if not self.stemming_dictionaries.get(dictionary_id): |
| 80 | + self.stemming_dictionaries[dictionary_id] = AsyncStemmingDictionary( |
| 81 | + self.api_call, |
| 82 | + dictionary_id, |
| 83 | + ) |
| 84 | + return self.stemming_dictionaries[dictionary_id] |
| 85 | + |
| 86 | + async def retrieve(self) -> StemmingDictionariesRetrieveSchema: |
| 87 | + """ |
| 88 | + Retrieve the list of stemming dictionaries. |
| 89 | +
|
| 90 | + Returns: |
| 91 | + StemmingDictionariesRetrieveSchema: The list of stemming dictionaries. |
| 92 | + """ |
| 93 | + response: StemmingDictionariesRetrieveSchema = await self.api_call.get( |
| 94 | + self._endpoint_path(), |
| 95 | + entity_type=StemmingDictionariesRetrieveSchema, |
| 96 | + ) |
| 97 | + return response |
| 98 | + |
| 99 | + @typing.overload |
| 100 | + async def upsert( |
| 101 | + self, |
| 102 | + dictionary_id: str, |
| 103 | + word_root_combinations: typing.Union[str, bytes], |
| 104 | + ) -> str: ... |
| 105 | + |
| 106 | + @typing.overload |
| 107 | + async def upsert( |
| 108 | + self, |
| 109 | + dictionary_id: str, |
| 110 | + word_root_combinations: typing.List[StemmingDictionaryCreateSchema], |
| 111 | + ) -> typing.List[StemmingDictionaryCreateSchema]: ... |
| 112 | + |
| 113 | + async def upsert( |
| 114 | + self, |
| 115 | + dictionary_id: str, |
| 116 | + word_root_combinations: typing.Union[ |
| 117 | + typing.List[StemmingDictionaryCreateSchema], |
| 118 | + str, |
| 119 | + bytes, |
| 120 | + ], |
| 121 | + ) -> typing.Union[str, typing.List[StemmingDictionaryCreateSchema]]: |
| 122 | + if isinstance(word_root_combinations, (str, bytes)): |
| 123 | + return await self._upsert_raw(dictionary_id, word_root_combinations) |
| 124 | + |
| 125 | + return await self._upsert_list(dictionary_id, word_root_combinations) |
| 126 | + |
| 127 | + async def _upsert_list( |
| 128 | + self, |
| 129 | + dictionary_id: str, |
| 130 | + word_root_combinations: typing.List[StemmingDictionaryCreateSchema], |
| 131 | + ) -> typing.List[StemmingDictionaryCreateSchema]: |
| 132 | + word_combos_in_jsonl = self._dump_to_jsonl(word_root_combinations) |
| 133 | + response = await self._upsert_raw(dictionary_id, word_combos_in_jsonl) |
| 134 | + return self._parse_response(response) |
| 135 | + |
| 136 | + def _dump_to_jsonl( |
| 137 | + self, |
| 138 | + word_root_combinations: typing.List[StemmingDictionaryCreateSchema], |
| 139 | + ) -> str: |
| 140 | + word_root_strs = [json.dumps(combo) for combo in word_root_combinations] |
| 141 | + |
| 142 | + return "\n".join(word_root_strs) |
| 143 | + |
| 144 | + def _parse_response( |
| 145 | + self, |
| 146 | + response: str, |
| 147 | + ) -> typing.List[StemmingDictionaryCreateSchema]: |
| 148 | + object_list: typing.List[StemmingDictionaryCreateSchema] = [] |
| 149 | + |
| 150 | + for line in response.split("\n"): |
| 151 | + try: |
| 152 | + decoded = json.loads(line) |
| 153 | + except json.JSONDecodeError as err: |
| 154 | + raise ValueError(f"Failed to parse JSON from response: {line}") from err |
| 155 | + object_list.append(decoded) |
| 156 | + return object_list |
| 157 | + |
| 158 | + async def _upsert_raw( |
| 159 | + self, |
| 160 | + dictionary_id: str, |
| 161 | + word_root_combinations: typing.Union[bytes, str], |
| 162 | + ) -> str: |
| 163 | + response: str = await self.api_call.post( |
| 164 | + self._endpoint_path("import"), |
| 165 | + body=word_root_combinations, |
| 166 | + as_json=False, |
| 167 | + entity_type=str, |
| 168 | + params={"id": dictionary_id}, |
| 169 | + ) |
| 170 | + return response |
| 171 | + |
| 172 | + def _endpoint_path(self, action: typing.Union[str, None] = None) -> str: |
| 173 | + """ |
| 174 | + Construct the API endpoint path for this specific stemming dictionary. |
| 175 | +
|
| 176 | + Args: |
| 177 | + action (str, optional): The action to perform on the stemming dictionary. |
| 178 | + Defaults to None. |
| 179 | +
|
| 180 | + Returns: |
| 181 | + str: The constructed endpoint path. |
| 182 | + """ |
| 183 | + if action: |
| 184 | + return f"{AsyncStemmingDictionaries.resource_path}/{action}" |
| 185 | + return AsyncStemmingDictionaries.resource_path |
0 commit comments