meilisearch-python-sdk 7.1.4__tar.gz → 7.2.0__tar.gz

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.
Files changed (112) hide show
  1. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.github/workflows/docs_publish.yml +14 -2
  2. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.github/workflows/testing.yml +4 -4
  3. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.pre-commit-config.yaml +3 -3
  4. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/PKG-INFO +2 -3
  5. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docker-compose.https.yml +1 -1
  6. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docker-compose.yml +1 -1
  7. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/justfile +2 -2
  8. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/_batch.py +2 -2
  9. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/_client/_async_client.py +26 -4
  10. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/_client/_base_client.py +2 -3
  11. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/_client/_client.py +26 -4
  12. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/_http_requests.py +1 -1
  13. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/_task.py +2 -2
  14. meilisearch_python_sdk-7.2.0/meilisearch_python_sdk/_utils.py +135 -0
  15. meilisearch_python_sdk-7.2.0/meilisearch_python_sdk/_version.py +1 -0
  16. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/errors.py +49 -1
  17. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/index/async_index.py +24 -3
  18. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/index/index.py +24 -3
  19. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/client.py +2 -2
  20. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/index.py +3 -0
  21. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/pyproject.toml +6 -8
  22. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/conftest.py +1 -1
  23. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_async_client.py +49 -9
  24. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_async_index.py +23 -1
  25. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_client.py +42 -9
  26. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_errors.py +3 -3
  27. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_index.py +23 -1
  28. meilisearch_python_sdk-7.2.0/tests/test_utils.py +260 -0
  29. meilisearch_python_sdk-7.2.0/uv.lock +1434 -0
  30. meilisearch_python_sdk-7.1.4/meilisearch_python_sdk/_utils.py +0 -34
  31. meilisearch_python_sdk-7.1.4/meilisearch_python_sdk/_version.py +0 -1
  32. meilisearch_python_sdk-7.1.4/uv.lock +0 -1561
  33. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.github/FUNDING.yml +0 -0
  34. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.github/release-draft-template.yaml +0 -0
  35. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.github/renovate.json5 +0 -0
  36. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.github/workflows/nightly_testing.yml +0 -0
  37. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.github/workflows/pypi_publish.yml +0 -0
  38. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.github/workflows/release-drafter.yml +0 -0
  39. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/.gitignore +0 -0
  40. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/CONTRIBUTING.md +0 -0
  41. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/LICENSE +0 -0
  42. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/README.md +0 -0
  43. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/assets/add_in_batches.png +0 -0
  44. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/assets/searches.png +0 -0
  45. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/codecov.yml +0 -0
  46. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/datasets/small_movies.json +0 -0
  47. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/.nojekyll +0 -0
  48. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/CNAME +0 -0
  49. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/async_client_api.md +0 -0
  50. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/async_index_api.md +0 -0
  51. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/client_api.md +0 -0
  52. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/css/custom.css +0 -0
  53. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/decorators_api.md +0 -0
  54. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/index.md +0 -0
  55. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/index_api.md +0 -0
  56. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/js/umami.js +0 -0
  57. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/json_handler.md +0 -0
  58. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/overrides/partials/footer.html +0 -0
  59. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/plugins.md +0 -0
  60. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/docs/pydantic.md +0 -0
  61. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/.gitignore +0 -0
  62. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/README.md +0 -0
  63. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/__init__.py +0 -0
  64. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/add_documents_decorator.py +0 -0
  65. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/add_documents_in_batches.py +0 -0
  66. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/async_add_documents_decorator.py +0 -0
  67. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/async_add_documents_in_batches.py +0 -0
  68. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/async_documents_and_search_results.py +0 -0
  69. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/async_search_tracker.py +0 -0
  70. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/async_update_settings.py +0 -0
  71. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/documents_and_search_results.py +0 -0
  72. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/fastapi_example.py +0 -0
  73. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/orjson_example.py +0 -0
  74. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/pyproject.toml +0 -0
  75. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/requirements.txt +0 -0
  76. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/search_tracker.py +0 -0
  77. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/tests/__init__.py +0 -0
  78. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/tests/conftest.py +0 -0
  79. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/tests/test_async_examples.py +0 -0
  80. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/tests/test_examples.py +0 -0
  81. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/examples/update_settings.py +0 -0
  82. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/__init__.py +0 -0
  83. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/_client/__init__.py +0 -0
  84. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/_client/_common.py +0 -0
  85. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/decorators.py +0 -0
  86. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/index/__init__.py +0 -0
  87. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/index/_common.py +0 -0
  88. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/json_handler.py +0 -0
  89. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/__init__.py +0 -0
  90. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/batch.py +0 -0
  91. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/documents.py +0 -0
  92. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/health.py +0 -0
  93. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/search.py +0 -0
  94. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/settings.py +0 -0
  95. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/task.py +0 -0
  96. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/version.py +0 -0
  97. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/models/webhook.py +0 -0
  98. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/plugins.py +0 -0
  99. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/py.typed +0 -0
  100. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/meilisearch_python_sdk/types.py +0 -0
  101. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/mkdocs.yaml +0 -0
  102. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/__init__.py +0 -0
  103. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_async_documents.py +0 -0
  104. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_async_index_plugins.py +0 -0
  105. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_async_search.py +0 -0
  106. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_decorators.py +0 -0
  107. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_documents.py +0 -0
  108. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_http_requests.py +0 -0
  109. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_index_plugins.py +0 -0
  110. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_search.py +0 -0
  111. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_settings_models.py +0 -0
  112. {meilisearch_python_sdk-7.1.4 → meilisearch_python_sdk-7.2.0}/tests/test_version.py +0 -0
@@ -6,9 +6,13 @@ on:
6
6
  workflow_dispatch:
7
7
  env:
8
8
  PYTHON_VERSION: "3.13"
9
+ permissions:
10
+ pages: write
11
+ id-token: write
9
12
  jobs:
10
13
  deploy:
11
14
  runs-on: ubuntu-latest
15
+ environment: github-pages
12
16
  steps:
13
17
  - uses: actions/checkout@v6
14
18
  - name: Install uv
@@ -21,5 +25,13 @@ jobs:
21
25
  python-version: ${{ env.PYTHON_VERSION }}
22
26
  - name: Install Dependencies
23
27
  run: uv sync --frozen --all-extras
24
- - name: Deploy Docs
25
- run: uv run mkdocs gh-deploy --force
28
+ - name: Configure Pages
29
+ uses: actions/configure-pages@v6
30
+ - name: Build Docs
31
+ run: uv run zensical build --strict
32
+ - name: Upload Pages Artifact
33
+ uses: actions/upload-pages-artifact@v5
34
+ with:
35
+ path: ./site
36
+ - name: Deploy to GitHub Pages
37
+ uses: actions/deploy-pages@v5
@@ -52,7 +52,7 @@ jobs:
52
52
  - name: Test with pytest
53
53
  run: just test-parallel-ci
54
54
  - name: Upload coverage
55
- uses: codecov/codecov-action@v6.0.0
55
+ uses: codecov/codecov-action@v6.0.1
56
56
  env:
57
57
  CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
58
58
  with:
@@ -93,7 +93,7 @@ jobs:
93
93
  - name: Test with pytest
94
94
  run: just test-parallel-ci-http2
95
95
  - name: Upload coverage
96
- uses: codecov/codecov-action@v6.0.0
96
+ uses: codecov/codecov-action@v6.0.1
97
97
  env:
98
98
  CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
99
99
  with:
@@ -123,7 +123,7 @@ jobs:
123
123
  - name: Test with pytest
124
124
  run: just test-no-parallel-ci
125
125
  - name: Upload coverage
126
- uses: codecov/codecov-action@v6.0.0
126
+ uses: codecov/codecov-action@v6.0.1
127
127
  env:
128
128
  CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
129
129
  with:
@@ -164,7 +164,7 @@ jobs:
164
164
  - name: Test with pytest
165
165
  run: just test-no-parallel-ci-http2
166
166
  - name: Upload coverage
167
- uses: codecov/codecov-action@v6.0.0
167
+ uses: codecov/codecov-action@v6.0.1
168
168
  env:
169
169
  CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
170
170
  with:
@@ -9,16 +9,16 @@ repos:
9
9
  - id: end-of-file-fixer
10
10
  - id: trailing-whitespace
11
11
  - repo: https://github.com/pre-commit/mirrors-mypy
12
- rev: v1.20.2
12
+ rev: v2.1.0
13
13
  hooks:
14
14
  - id: mypy
15
15
  additional_dependencies: [pydantic, orjson, types-aiofiles, types-ujson]
16
16
  - repo: https://github.com/astral-sh/ruff-pre-commit
17
- rev: v0.15.12
17
+ rev: v0.15.14
18
18
  hooks:
19
19
  - id: ruff-check
20
20
  args: [--fix, --exit-non-zero-on-fix]
21
21
  - repo: https://github.com/rvben/rumdl-pre-commit
22
- rev: v0.1.83
22
+ rev: v0.2.2
23
23
  hooks:
24
24
  - id: rumdl-fmt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meilisearch-python-sdk
3
- Version: 7.1.4
3
+ Version: 7.2.0
4
4
  Summary: A Python client providing both async and sync support for the Meilisearch API
5
5
  Project-URL: repository, https://github.com/sanders41/meilisearch-python-sdk
6
6
  Project-URL: homepage, https://github.com/sanders41/meilisearch-python-sdk
@@ -42,9 +42,8 @@ Classifier: Typing :: Typed
42
42
  Requires-Python: >=3.10
43
43
  Requires-Dist: aiofiles>=0.7
44
44
  Requires-Dist: camel-converter[pydantic]>=1.0.0
45
- Requires-Dist: httpx[http2]>=0.17
45
+ Requires-Dist: httpx2[http2]>=2.0.0
46
46
  Requires-Dist: pydantic>=2.0.0
47
- Requires-Dist: pyjwt>=2.3.0
48
47
  Provides-Extra: all
49
48
  Requires-Dist: orjson; extra == 'all'
50
49
  Provides-Extra: orjson
@@ -1,6 +1,6 @@
1
1
  services:
2
2
  meilisearch:
3
- image: getmeili/meilisearch:v1.42.1
3
+ image: getmeili/meilisearch:v1.45.0
4
4
  ports:
5
5
  - "7700:7700"
6
6
  environment:
@@ -1,6 +1,6 @@
1
1
  services:
2
2
  meilisearch:
3
- image: getmeili/meilisearch:v1.42.1
3
+ image: getmeili/meilisearch:v1.45.0
4
4
  ports:
5
5
  - "7700:7700"
6
6
  environment:
@@ -81,10 +81,10 @@
81
81
  docker compose -f docker-compose.https.yml down
82
82
 
83
83
  @build-docs:
84
- uv run mkdocs build --strict
84
+ uv run zensical build --strict
85
85
 
86
86
  @serve-docs:
87
- uv run mkdocs serve
87
+ uv run zensical serve
88
88
 
89
89
  @install:
90
90
  uv sync --frozen --all-extras
@@ -10,8 +10,8 @@ from meilisearch_python_sdk.errors import BatchNotFoundError, MeilisearchApiErro
10
10
  from meilisearch_python_sdk.models.batch import BatchResult, BatchStatus
11
11
 
12
12
  if TYPE_CHECKING:
13
- from httpx import AsyncClient as HttpxAsyncClient # pragma: no cover
14
- from httpx import Client as HttpxClient # pragma: no cover
13
+ from httpx2 import AsyncClient as HttpxAsyncClient # pragma: no cover
14
+ from httpx2 import Client as HttpxClient # pragma: no cover
15
15
 
16
16
  from meilisearch_python_sdk._client import ( # pragma: no cover
17
17
  AsyncClient,
@@ -1,10 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from datetime import datetime
4
- from typing import TYPE_CHECKING, Any
4
+ from typing import TYPE_CHECKING, Any, Literal
5
5
 
6
6
  from camel_converter import dict_to_camel
7
- from httpx import AsyncClient as HttpxAsyncClient
7
+ from httpx2 import AsyncClient as HttpxAsyncClient
8
8
 
9
9
  from meilisearch_python_sdk import _task
10
10
  from meilisearch_python_sdk._batch import async_get_batch, async_get_batches
@@ -501,9 +501,22 @@ class AsyncClient(BaseClient):
501
501
  hits_type=hits_type,
502
502
  )
503
503
 
504
- async def get_all_stats(self) -> ClientStats:
504
+ async def get_all_stats(
505
+ self,
506
+ *,
507
+ show_internal_database_sizes: bool = False,
508
+ size_format: Literal["human", "raw"] | None = None,
509
+ ) -> ClientStats:
505
510
  """Get stats for all indexes.
506
511
 
512
+ Args:
513
+ show_internal_database_sizes: Include internal database size inforamation in results.
514
+ Default = False.
515
+ size_format: When present and set to human, then all database sizes in responses of the
516
+ stat routes will be returned as a string containing an appropriate unit (MiB, GiB,
517
+ etc). When missing or set to raw, then the current behavior of expressing the size
518
+ in bytes as a number is retained. Default = None
519
+
507
520
  Returns:
508
521
  Information about database size and all indexes.
509
522
 
@@ -516,7 +529,16 @@ class AsyncClient(BaseClient):
516
529
  >>> async with AsyncClient("http://localhost.com", "masterKey") as client:
517
530
  >>> stats = await client.get_all_stats()
518
531
  """
519
- response = await self._http_requests.get("stats")
532
+ url = "stats"
533
+
534
+ if show_internal_database_sizes:
535
+ url = f"{url}?showInternalDatabaseSizes=true"
536
+ if size_format:
537
+ url = f"{url}&sizeFormat={size_format}"
538
+ elif not show_internal_database_sizes and size_format:
539
+ url = f"{url}?sizeFormat={size_format}"
540
+
541
+ response = await self._http_requests.get(url)
520
542
 
521
543
  return ClientStats(**self._http_requests.parse_json(response))
522
544
 
@@ -3,8 +3,7 @@ from __future__ import annotations
3
3
  from datetime import datetime, timezone
4
4
  from typing import TYPE_CHECKING
5
5
 
6
- import jwt
7
-
6
+ from meilisearch_python_sdk._utils import encode_jwt
8
7
  from meilisearch_python_sdk.errors import InvalidRestriction
9
8
  from meilisearch_python_sdk.json_handler import BuiltinHandler, OrjsonHandler
10
9
  from meilisearch_python_sdk.models.client import (
@@ -101,4 +100,4 @@ class BaseClient:
101
100
 
102
101
  payload["exp"] = int(datetime.timestamp(expires_at))
103
102
 
104
- return jwt.encode(payload, api_key.key, algorithm="HS256")
103
+ return encode_jwt(payload=payload, key=api_key.key, json_handler=self.json_handler)
@@ -1,10 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from datetime import datetime
4
- from typing import TYPE_CHECKING, Any
4
+ from typing import TYPE_CHECKING, Any, Literal
5
5
 
6
6
  from camel_converter import dict_to_camel
7
- from httpx import Client as HttpxClient
7
+ from httpx2 import Client as HttpxClient
8
8
 
9
9
  from meilisearch_python_sdk import _task
10
10
  from meilisearch_python_sdk._batch import get_batch as _get_batch
@@ -505,9 +505,22 @@ class Client(BaseClient):
505
505
  hits_type=hits_type,
506
506
  )
507
507
 
508
- def get_all_stats(self) -> ClientStats:
508
+ def get_all_stats(
509
+ self,
510
+ *,
511
+ show_internal_database_sizes: bool = False,
512
+ size_format: Literal["human", "raw"] | None = None,
513
+ ) -> ClientStats:
509
514
  """Get stats for all indexes.
510
515
 
516
+ Args:
517
+ show_internal_database_sizes: Include internal database size inforamation in results.
518
+ Default = False.
519
+ size_format: When present and set to human, then all database sizes in responses of the
520
+ stat routes will be returned as a string containing an appropriate unit (MiB, GiB,
521
+ etc). When missing or set to raw, then the current behavior of expressing the size
522
+ in bytes as a number is retained. Default = None
523
+
511
524
  Returns:
512
525
  Information about database size and all indexes.
513
526
 
@@ -520,7 +533,16 @@ class Client(BaseClient):
520
533
  >>> with Client("http://localhost.com", "masterKey") as client:
521
534
  >>> stats = client.get_all_stats()
522
535
  """
523
- response = self._http_requests.get("stats")
536
+ url = "stats"
537
+
538
+ if show_internal_database_sizes:
539
+ url = f"{url}?showInternalDatabaseSizes=true"
540
+ if size_format:
541
+ url = f"{url}&sizeFormat={size_format}"
542
+ elif not show_internal_database_sizes and size_format:
543
+ url = f"{url}?sizeFormat={size_format}"
544
+
545
+ response = self._http_requests.get(url)
524
546
 
525
547
  return ClientStats(**self._http_requests.parse_json(response))
526
548
 
@@ -4,7 +4,7 @@ import gzip
4
4
  from functools import lru_cache
5
5
  from typing import TYPE_CHECKING, Any
6
6
 
7
- from httpx import (
7
+ from httpx2 import (
8
8
  AsyncClient,
9
9
  Client,
10
10
  ConnectError,
@@ -6,8 +6,8 @@ from datetime import datetime
6
6
  from typing import TYPE_CHECKING
7
7
  from urllib.parse import urlencode
8
8
 
9
- from httpx import AsyncClient as HttpxAsyncClient
10
- from httpx import Client as HttpxClient
9
+ from httpx2 import AsyncClient as HttpxAsyncClient
10
+ from httpx2 import Client as HttpxClient
11
11
 
12
12
  from meilisearch_python_sdk._http_requests import AsyncHttpRequests, HttpRequests
13
13
  from meilisearch_python_sdk._utils import get_async_client, get_client
@@ -0,0 +1,135 @@
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import hashlib
5
+ import hmac
6
+ import sys
7
+ from calendar import timegm
8
+ from datetime import datetime, timezone
9
+ from functools import lru_cache
10
+ from typing import TYPE_CHECKING
11
+
12
+ from httpx2 import AsyncClient as HttpxAsyncClient
13
+ from httpx2 import Client as HttpxClient
14
+
15
+ from meilisearch_python_sdk.errors import (
16
+ DecodeError,
17
+ ExpiredSignatureError,
18
+ ImmatureSignatureError,
19
+ InvalidIssuedAtError,
20
+ InvalidJTIError,
21
+ InvalidSignatureError,
22
+ InvalidSubjectError,
23
+ )
24
+ from meilisearch_python_sdk.json_handler import BuiltinHandler, OrjsonHandler
25
+
26
+ if TYPE_CHECKING:
27
+ from meilisearch_python_sdk._client import AsyncClient, Client
28
+ from meilisearch_python_sdk.types import JsonDict
29
+
30
+
31
+ def get_async_client(
32
+ client: AsyncClient | HttpxAsyncClient,
33
+ ) -> HttpxAsyncClient:
34
+ if isinstance(client, HttpxAsyncClient):
35
+ return client
36
+
37
+ return client.http_client
38
+
39
+
40
+ def get_client(
41
+ client: Client | HttpxClient,
42
+ ) -> HttpxClient:
43
+ if isinstance(client, HttpxClient):
44
+ return client
45
+
46
+ return client.http_client
47
+
48
+
49
+ @lru_cache(maxsize=1)
50
+ def use_task_groups() -> bool:
51
+ return True if sys.version_info >= (3, 11) else False
52
+
53
+
54
+ def _jwt_b64encode(data: bytes) -> str:
55
+ return base64.urlsafe_b64encode(data).rstrip(b"=").decode()
56
+
57
+
58
+ def encode_jwt(*, payload: JsonDict, key: str, json_handler: BuiltinHandler | OrjsonHandler) -> str:
59
+ if not isinstance(payload, dict):
60
+ raise TypeError("Expecting a dict object, as JWT only supports JSON objects as payloads.")
61
+
62
+ payload = payload.copy()
63
+
64
+ for time_claim in ("exp", "iat", "nbf"):
65
+ if isinstance(payload.get(time_claim), datetime):
66
+ payload[time_claim] = timegm(payload[time_claim].utctimetuple())
67
+
68
+ if "iss" in payload and not isinstance(payload["iss"], str):
69
+ raise TypeError("Issuer (iss) must be a string.")
70
+
71
+ typ = "secevent+jwt" if "events" in payload else "JWT"
72
+ header = _jwt_b64encode(json_handler.dump_bytes({"alg": "HS256", "typ": typ}))
73
+ body = _jwt_b64encode(json_handler.dump_bytes(payload))
74
+ message = f"{header}.{body}"
75
+ sig = _jwt_b64encode(hmac.new(key.encode(), message.encode(), hashlib.sha256).digest())
76
+
77
+ return f"{message}.{sig}"
78
+
79
+
80
+ def decode_jwt(
81
+ *, token: str, key: str, json_handler: BuiltinHandler | OrjsonHandler, leeway: float = 0
82
+ ) -> JsonDict:
83
+ header_b64, payload_b64, sig_b64 = token.split(".")
84
+ message = f"{header_b64}.{payload_b64}"
85
+ expected = _jwt_b64encode(hmac.new(key.encode(), message.encode(), hashlib.sha256).digest())
86
+
87
+ if not hmac.compare_digest(sig_b64, expected):
88
+ raise InvalidSignatureError("Signature verification failed")
89
+
90
+ padding = "=" * (4 - len(payload_b64) % 4)
91
+
92
+ try:
93
+ payload = json_handler.loads(base64.urlsafe_b64decode(payload_b64 + padding))
94
+ except Exception as e:
95
+ raise DecodeError(f"Invalid payload string: {e}") from e
96
+
97
+ if not isinstance(payload, dict):
98
+ raise DecodeError("Invalid payload string: must be a json object")
99
+
100
+ now = datetime.now(tz=timezone.utc).timestamp()
101
+
102
+ if "iat" in payload:
103
+ try:
104
+ iat = int(payload["iat"])
105
+ except (ValueError, TypeError):
106
+ raise InvalidIssuedAtError("Issued At claim (iat) must be an integer.") from None
107
+
108
+ if iat > (now + leeway):
109
+ raise ImmatureSignatureError("The token is not yet valid (iat)")
110
+
111
+ if "nbf" in payload:
112
+ try:
113
+ nbf = int(payload["nbf"])
114
+ except (ValueError, TypeError):
115
+ raise DecodeError("Not Before claim (nbf) must be an integer.") from None
116
+
117
+ if nbf > (now + leeway):
118
+ raise ImmatureSignatureError("The token is not yet valid (nbf)")
119
+
120
+ if "exp" in payload:
121
+ try:
122
+ exp = int(payload["exp"])
123
+ except (ValueError, TypeError):
124
+ raise DecodeError("Expiration Time claim (exp) must be an integer.") from None
125
+
126
+ if exp <= (now - leeway):
127
+ raise ExpiredSignatureError("Signature has expired")
128
+
129
+ if "sub" in payload and not isinstance(payload["sub"], str):
130
+ raise InvalidSubjectError("Subject must be a string")
131
+
132
+ if "jti" in payload and not isinstance(payload["jti"], str):
133
+ raise InvalidJTIError("JWT ID must be a string")
134
+
135
+ return payload
@@ -0,0 +1 @@
1
+ VERSION = "7.2.0"
@@ -1,4 +1,4 @@
1
- from httpx import Response
1
+ from httpx2 import Response
2
2
 
3
3
 
4
4
  class BatchNotFoundError(Exception):
@@ -74,3 +74,51 @@ class PayloadTooLarge(Exception):
74
74
  """Error when the payload is larger than the allowed payload size."""
75
75
 
76
76
  pass
77
+
78
+
79
+ class InvalidTokenError(Exception):
80
+ """Base exception when ``decode()`` fails on a token"""
81
+
82
+ pass
83
+
84
+
85
+ class DecodeError(InvalidTokenError):
86
+ """Raised when a token cannot be decoded because it failed validation"""
87
+
88
+ pass
89
+
90
+
91
+ class InvalidIssuedAtError(InvalidTokenError):
92
+ """Raised when a token's ``iat`` claim is non-numeric"""
93
+
94
+ pass
95
+
96
+
97
+ class InvalidSignatureError(DecodeError):
98
+ """Raised when a token's signature doesn't match the one provided as part of the token."""
99
+
100
+ pass
101
+
102
+
103
+ class ImmatureSignatureError(InvalidTokenError):
104
+ """Raised when a token's ``nbf`` or ``iat`` claims represent a time in the future"""
105
+
106
+ pass
107
+
108
+
109
+ class ExpiredSignatureError(InvalidTokenError):
110
+ """Raised when a token's ``exp`` claim indicates it has expired"""
111
+
112
+ pass
113
+
114
+
115
+ class InvalidSubjectError(InvalidTokenError):
116
+ """Raised when a token's ``sub`` claim is not a string"""
117
+
118
+ pass
119
+
120
+
121
+ class InvalidJTIError(InvalidTokenError):
122
+ """Raised when a token's ``jti`` claim is not a string"""
123
+
124
+ pass
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, Any, Literal
9
9
 
10
10
  import aiofiles
11
11
  from camel_converter import to_snake
12
- from httpx import AsyncClient
12
+ from httpx2 import AsyncClient
13
13
 
14
14
  from meilisearch_python_sdk._http_requests import AsyncHttpRequests
15
15
  from meilisearch_python_sdk._task import async_wait_for_task
@@ -521,9 +521,22 @@ class AsyncIndex(BaseIndex):
521
521
 
522
522
  return index
523
523
 
524
- async def get_stats(self) -> IndexStats:
524
+ async def get_stats(
525
+ self,
526
+ *,
527
+ show_internal_database_sizes: bool = False,
528
+ size_format: Literal["human", "raw"] | None = None,
529
+ ) -> IndexStats:
525
530
  """Get stats of the index.
526
531
 
532
+ Args:
533
+ show_internal_database_sizes: Include internal database size inforamation in results.
534
+ Default = False.
535
+ size_format: When present and set to human, then all database sizes in responses of the
536
+ stat routes will be returned as a string containing an appropriate unit (MiB, GiB,
537
+ etc). When missing or set to raw, then the current behavior of expressing the size
538
+ in bytes as a number is retained. Default = None
539
+
527
540
  Returns:
528
541
  Stats of the index.
529
542
 
@@ -537,7 +550,15 @@ class AsyncIndex(BaseIndex):
537
550
  >>> index = client.index("movies")
538
551
  >>> stats = await index.get_stats()
539
552
  """
540
- response = await self._http_requests.get(self._stats_url)
553
+ url = self._stats_url
554
+ if show_internal_database_sizes:
555
+ url = f"{url}?showInternalDatabaseSizes=true"
556
+ if size_format:
557
+ url = f"{url}&sizeFormat={size_format}"
558
+ elif not show_internal_database_sizes and size_format:
559
+ url = f"{url}?sizeFormat={size_format}"
560
+
561
+ response = await self._http_requests.get(url)
541
562
 
542
563
  return IndexStats(**self._http_requests.parse_json(response))
543
564
 
@@ -7,7 +7,7 @@ from pathlib import Path
7
7
  from typing import TYPE_CHECKING, Any, Literal
8
8
 
9
9
  from camel_converter import to_snake
10
- from httpx import Client
10
+ from httpx2 import Client
11
11
 
12
12
  from meilisearch_python_sdk._http_requests import HttpRequests
13
13
  from meilisearch_python_sdk._task import wait_for_task
@@ -459,9 +459,22 @@ class Index(BaseIndex):
459
459
 
460
460
  return index
461
461
 
462
- def get_stats(self) -> IndexStats:
462
+ def get_stats(
463
+ self,
464
+ *,
465
+ show_internal_database_sizes: bool = False,
466
+ size_format: Literal["human", "raw"] | None = None,
467
+ ) -> IndexStats:
463
468
  """Get stats of the index.
464
469
 
470
+ Args:
471
+ show_internal_database_sizes: Include internal database size inforamation in results.
472
+ Default = False.
473
+ size_format: When present and set to human, then all database sizes in responses of the
474
+ stat routes will be returned as a string containing an appropriate unit (MiB, GiB,
475
+ etc). When missing or set to raw, then the current behavior of expressing the size
476
+ in bytes as a number is retained. Default = None
477
+
465
478
  Returns:
466
479
  Stats of the index.
467
480
 
@@ -475,7 +488,15 @@ class Index(BaseIndex):
475
488
  >>> index = client.index("movies")
476
489
  >>> stats = index.get_stats()
477
490
  """
478
- response = self._http_requests.get(self._stats_url)
491
+ url = self._stats_url
492
+ if show_internal_database_sizes:
493
+ url = f"{url}?showInternalDatabaseSizes=true"
494
+ if size_format:
495
+ url = f"{url}&sizeFormat={size_format}"
496
+ elif not show_internal_database_sizes and size_format:
497
+ url = f"{url}?sizeFormat={size_format}"
498
+
499
+ response = self._http_requests.get(url)
479
500
 
480
501
  return IndexStats(**self._http_requests.parse_json(response))
481
502
 
@@ -10,8 +10,8 @@ from meilisearch_python_sdk.models.index import IndexStats
10
10
 
11
11
 
12
12
  class ClientStats(CamelBase):
13
- database_size: int
14
- used_database_size: int | None = None
13
+ database_size: int | str
14
+ used_database_size: int | str | None = None
15
15
  last_update: datetime | None = None
16
16
  indexes: dict[str, IndexStats] | None = None
17
17
 
@@ -4,6 +4,8 @@ from datetime import datetime
4
4
 
5
5
  from camel_converter.pydantic_base import CamelBase
6
6
 
7
+ from meilisearch_python_sdk.types import JsonDict
8
+
7
9
 
8
10
  class IndexBase(CamelBase):
9
11
  uid: str
@@ -21,6 +23,7 @@ class IndexStats(CamelBase):
21
23
  number_of_embeddings: int | None = None
22
24
  is_indexing: bool
23
25
  field_distribution: dict[str, int]
26
+ internal_database_sizes: JsonDict | None = None
24
27
 
25
28
 
26
29
  class FieldsFilter(CamelBase):
@@ -26,9 +26,8 @@ dynamic = ["version"]
26
26
  dependencies = [
27
27
  "aiofiles>=0.7",
28
28
  "camel-converter[pydantic]>=1.0.0",
29
- "httpx[http2]>=0.17",
29
+ "httpx2[http2]>=2.0.0",
30
30
  "pydantic>=2.0.0",
31
- "PyJWT>=2.3.0",
32
31
  ]
33
32
 
34
33
  [project.optional-dependencies]
@@ -37,18 +36,17 @@ all = ["orjson"]
37
36
 
38
37
  [dependency-groups]
39
38
  dev = [
40
- "mkdocs==1.6.1",
41
- "mkdocs-material==9.7.6",
42
39
  "mkdocstrings[python]==1.0.4",
43
- "mypy[faster-cache]>=1.19.1",
40
+ "mypy[faster-cache]==2.1.0",
44
41
  "pytest==9.0.3",
45
42
  "pytest-cov==7.1.0",
46
- "pytest-asyncio==1.3.0",
43
+ "pytest-asyncio==1.4.0",
47
44
  "pytest-xdist==3.8.0",
48
45
  "prek>=0.2.27",
49
- "ruff==0.15.12",
50
- "types-aiofiles==25.1.0.20260409",
46
+ "ruff==0.15.14",
47
+ "types-aiofiles==25.1.0.20260518",
51
48
  "typing-extensions==4.15.0",
49
+ "zensical>=0.0.43",
52
50
  ]
53
51
 
54
52
  [tool.hatch.version]
@@ -13,7 +13,7 @@ try:
13
13
  except ImportError:
14
14
  truststore = None
15
15
 
16
- from httpx import AsyncClient as HttpxAsyncClient
16
+ from httpx2 import AsyncClient as HttpxAsyncClient
17
17
 
18
18
  from meilisearch_python_sdk import AsyncClient, Client
19
19
  from meilisearch_python_sdk._task import async_wait_for_task, wait_for_task