diff --git a/meilisearch/index.py b/meilisearch/index.py index 7504e722..4fc43eeb 100644 --- a/meilisearch/index.py +++ b/meilisearch/index.py @@ -269,7 +269,7 @@ def get_stats(self) -> IndexStats: An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors """ stats = self.http.get(f"{self.config.paths.index}/{self.uid}/{self.config.paths.stat}") - return IndexStats(stats) + return IndexStats(**stats) @version_error_hint_message def search(self, query: str, opt_params: Optional[Mapping[str, Any]] = None) -> Dict[str, Any]: @@ -364,7 +364,7 @@ def get_document( """ if parameters is None: parameters = {} - elif "fields" in parameters and isinstance(parameters["fields"], list): + elif "fields" in parameters and isinstance(parameters["fields"], (list, tuple)): parameters["fields"] = ",".join(parameters["fields"]) document = self.http.get( diff --git a/meilisearch/models/index.py b/meilisearch/models/index.py index bee521ed..19f807fb 100644 --- a/meilisearch/models/index.py +++ b/meilisearch/models/index.py @@ -3,23 +3,19 @@ from enum import Enum from typing import Any, Dict, Iterator, List, Optional, Union -from camel_converter import to_snake from camel_converter.pydantic_base import CamelBase +from pydantic import ConfigDict, field_validator -class IndexStats: +class FieldDistribution: __dict: Dict - def __init__(self, doc: Dict[str, Any]) -> None: - self.__dict = doc - for key, val in doc.items(): - key = to_snake(key) - if isinstance(val, dict): - setattr(self, key, IndexStats(val)) - else: - setattr(self, key, val) + def __init__(self, dist: Dict[str, int]) -> None: + self.__dict = dist + for key in dist: + setattr(self, key, dist[key]) - def __getattr__(self, attr: str) -> Any: + def __getattr__(self, attr: str) -> str: if attr in self.__dict.keys(): return attr raise AttributeError(f"{self.__class__.__name__} object has no attribute {attr}") @@ -28,6 +24,22 @@ def __iter__(self) -> Iterator: return iter(self.__dict__.items()) +class IndexStats(CamelBase): + model_config = ConfigDict(arbitrary_types_allowed=True) + + number_of_documents: int + is_indexing: bool + field_distribution: FieldDistribution + + @field_validator("field_distribution", mode="before") + @classmethod + def build_field_distribution(cls, v: Any) -> FieldDistribution: + if not isinstance(v, dict): + raise TypeError('"field_distribution" in IndexStats must be a dict') + + return FieldDistribution(v) + + class Faceting(CamelBase): max_values_per_facet: int sort_facet_values_by: Optional[Dict[str, str]] = None diff --git a/meilisearch/models/task.py b/meilisearch/models/task.py index b8f0d68e..2b65c509 100644 --- a/meilisearch/models/task.py +++ b/meilisearch/models/task.py @@ -106,13 +106,12 @@ def validate_enqueued_at(cls, v: str) -> datetime: # pylint: disable=invalid-na return converted -class TaskResults: - def __init__(self, resp: Dict[str, Any]) -> None: - self.results: List[Task] = [Task(**task) for task in resp["results"]] - self.limit: int = resp["limit"] - self.total: int = resp["total"] - self.from_: int = resp["from"] - self.next_: int = resp["next"] +class TaskResults(CamelBase): + results: List[Task] + limit: int + total: int + from_: int + next_: Optional[int] class Batch(CamelBase): diff --git a/meilisearch/task.py b/meilisearch/task.py index 22900fbb..e492bd41 100644 --- a/meilisearch/task.py +++ b/meilisearch/task.py @@ -96,10 +96,10 @@ def get_tasks(self, parameters: Optional[MutableMapping[str, Any]] = None) -> Ta if parameters is None: parameters = {} for param in parameters: - if isinstance(parameters[param], list): + if isinstance(parameters[param], (list, tuple)): parameters[param] = ",".join(parameters[param]) tasks = self.http.get(f"{self.config.paths.task}?{parse.urlencode(parameters)}") - return TaskResults(tasks) + return TaskResults(**tasks) def get_task(self, uid: int) -> Task: """Get one task. @@ -142,7 +142,7 @@ def cancel_tasks(self, parameters: MutableMapping[str, Any]) -> TaskInfo: An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors """ for param in parameters: - if isinstance(parameters[param], list): + if isinstance(parameters[param], (list, tuple)): parameters[param] = ",".join(parameters[param]) response = self.http.post(f"{self.config.paths.task}/cancel?{parse.urlencode(parameters)}") return TaskInfo(**response) @@ -166,7 +166,7 @@ def delete_tasks(self, parameters: MutableMapping[str, Any]) -> TaskInfo: An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors """ for param in parameters: - if isinstance(parameters[param], list): + if isinstance(parameters[param], (list, tuple)): parameters[param] = ",".join(parameters[param]) response = self.http.delete(f"{self.config.paths.task}?{parse.urlencode(parameters)}") return TaskInfo(**response) diff --git a/tests/models/test_index.py b/tests/models/test_index.py deleted file mode 100644 index d3702e51..00000000 --- a/tests/models/test_index.py +++ /dev/null @@ -1,27 +0,0 @@ -# pylint: disable=unnecessary-dunder-call - -import pytest - -from meilisearch.models.index import IndexStats - - -def test_getattr(): - document = IndexStats({"field1": "test 1", "fiels2": "test 2"}) - assert document.__getattr__("field1") == "field1" - - -def test_getattr_not_found(): - document = IndexStats({"field1": "test 1", "fiels2": "test 2"}) - with pytest.raises(AttributeError): - document.__getattr__("bad") - - -def test_iter(): - # I wrote a test what what this does, but I have a feeling this isn't actually what it was - # expected to do when written as it doesn't really act like I would expect an iterator to act. - document = IndexStats({"field1": "test 1", "fiels2": "test 2"}) - - assert next(document.__iter__()) == ( - "_IndexStats__dict", - {"field1": "test 1", "fiels2": "test 2"}, - )