hubmap-search-sdk 1.0.0a12__tar.gz → 1.0.0a14__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.
- hubmap_search_sdk-1.0.0a14/.release-please-manifest.json +3 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/CHANGELOG.md +44 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/CONTRIBUTING.md +1 -2
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/PKG-INFO +37 -3
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/README.md +33 -2
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/bin/check-release-environment +1 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/pyproject.toml +5 -2
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/requirements-dev.lock +31 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/requirements.lock +27 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/__init__.py +2 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_base_client.py +44 -2
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_models.py +2 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_types.py +2 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_version.py +1 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_add.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_clear_docs.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_indices.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_mapping.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_mget.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_param_search.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_reindex.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_scroll_search.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_search.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_update.py +3 -1
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/conftest.py +36 -5
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_client.py +114 -15
- hubmap_search_sdk-1.0.0a12/.release-please-manifest.json +0 -3
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/.gitignore +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/LICENSE +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/SECURITY.md +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/api.md +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/bin/publish-pypi +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/examples/.keep +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/mypy.ini +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/noxfile.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/release-please-config.json +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_client.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_compat.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_constants.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_exceptions.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_files.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_qs.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_resource.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_response.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_streaming.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/__init__.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_logs.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_proxy.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_reflection.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_resources_proxy.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_streams.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_sync.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_transform.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_typing.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_utils.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/lib/.keep +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/py.typed +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/__init__.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/add.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/clear_docs.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/indices.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/mapping.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/mget.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/param_search.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/reindex.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/scroll_search.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/search.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/update.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/__init__.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/add_create_document_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/add_create_document_with_index_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/add_update_document_with_scope_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/index_list_response.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/mget_retrieve_multiple_by_index_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/mget_retrieve_multiple_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/param_search_execute_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/scroll_search_create_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/search_execute_index_query_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/search_execute_query_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/update_update_document_at_index_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/update_update_document_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/update_update_document_with_scope_params.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/__init__.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/__init__.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/sample_file.txt +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_deepcopy.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_extract_files.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_files.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_models.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_qs.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_required_args.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_response.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_streaming.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_transform.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_utils/test_proxy.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/test_utils/test_typing.py +0 -0
- {hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/utils.py +0 -0
@@ -1,5 +1,49 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.0.0-alpha.14 (2025-06-28)
|
4
|
+
|
5
|
+
Full Changelog: [v1.0.0-alpha.13...v1.0.0-alpha.14](https://github.com/hubmapconsortium/search-python-sdk/compare/v1.0.0-alpha.13...v1.0.0-alpha.14)
|
6
|
+
|
7
|
+
### Features
|
8
|
+
|
9
|
+
* **client:** add support for aiohttp ([2e47165](https://github.com/hubmapconsortium/search-python-sdk/commit/2e47165ede72e1dbd891097afa5fe5cc23790b79))
|
10
|
+
|
11
|
+
|
12
|
+
### Bug Fixes
|
13
|
+
|
14
|
+
* **ci:** release-doctor — report correct token name ([33bf6f7](https://github.com/hubmapconsortium/search-python-sdk/commit/33bf6f7dbf29f9b4d2747e09bf9ef848b0411fea))
|
15
|
+
* **client:** correctly parse binary response | stream ([e9dc865](https://github.com/hubmapconsortium/search-python-sdk/commit/e9dc8654daf52a63214e8575307e25b9c748506e))
|
16
|
+
* **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([854e415](https://github.com/hubmapconsortium/search-python-sdk/commit/854e41578698efee91b595e702721c1570ecebd5))
|
17
|
+
|
18
|
+
|
19
|
+
### Chores
|
20
|
+
|
21
|
+
* **ci:** enable for pull requests ([e7be8b2](https://github.com/hubmapconsortium/search-python-sdk/commit/e7be8b27cda54e12afc5e2936e1238c8dd3f5657))
|
22
|
+
* **ci:** only run for pushes and fork pull requests ([1d726a4](https://github.com/hubmapconsortium/search-python-sdk/commit/1d726a486601f809f7ea796b3e26b288f04422b6))
|
23
|
+
* **internal:** update conftest.py ([4ea44f2](https://github.com/hubmapconsortium/search-python-sdk/commit/4ea44f2d19f71d20b997cf49fc659819a80f7786))
|
24
|
+
* **readme:** update badges ([82fcb23](https://github.com/hubmapconsortium/search-python-sdk/commit/82fcb23a979d8dd8620ea9a6733f9aa661b6fae5))
|
25
|
+
* **tests:** add tests for httpx client instantiation & proxies ([2e2d7ac](https://github.com/hubmapconsortium/search-python-sdk/commit/2e2d7ace3a416e7f6805d75c0ca8878508be9434))
|
26
|
+
* **tests:** run tests in parallel ([ada43cc](https://github.com/hubmapconsortium/search-python-sdk/commit/ada43cc98977f550f9c8a8f2a27bd53dcb0a0697))
|
27
|
+
* **tests:** skip some failing tests on the latest python versions ([e8a90b8](https://github.com/hubmapconsortium/search-python-sdk/commit/e8a90b8b85442856af633c0c6b663d000c7fc8f8))
|
28
|
+
|
29
|
+
|
30
|
+
### Documentation
|
31
|
+
|
32
|
+
* **client:** fix httpx.Timeout documentation reference ([5e38f78](https://github.com/hubmapconsortium/search-python-sdk/commit/5e38f78a35147577cbc911fc19804fe430d2cd6f))
|
33
|
+
|
34
|
+
## 1.0.0-alpha.13 (2025-06-03)
|
35
|
+
|
36
|
+
Full Changelog: [v1.0.0-alpha.12...v1.0.0-alpha.13](https://github.com/hubmapconsortium/search-python-sdk/compare/v1.0.0-alpha.12...v1.0.0-alpha.13)
|
37
|
+
|
38
|
+
### Features
|
39
|
+
|
40
|
+
* **client:** add follow_redirects request option ([55b10c1](https://github.com/hubmapconsortium/search-python-sdk/commit/55b10c18cfea334e5ea9558f70ded70c2b21e34c))
|
41
|
+
|
42
|
+
|
43
|
+
### Chores
|
44
|
+
|
45
|
+
* **docs:** remove reference to rye shell ([ef26230](https://github.com/hubmapconsortium/search-python-sdk/commit/ef262304d809361ee6d56932bdb9328157e8aef6))
|
46
|
+
|
3
47
|
## 1.0.0-alpha.12 (2025-05-28)
|
4
48
|
|
5
49
|
Full Changelog: [v1.0.0-alpha.11...v1.0.0-alpha.12](https://github.com/hubmapconsortium/search-python-sdk/compare/v1.0.0-alpha.11...v1.0.0-alpha.12)
|
@@ -17,8 +17,7 @@ $ rye sync --all-features
|
|
17
17
|
You can then run scripts using `rye run python script.py` or by activating the virtual environment:
|
18
18
|
|
19
19
|
```sh
|
20
|
-
|
21
|
-
# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work
|
20
|
+
# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work
|
22
21
|
$ source .venv/bin/activate
|
23
22
|
|
24
23
|
# now you can omit the `rye run` prefix
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: hubmap_search_sdk
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.0a14
|
4
4
|
Summary: The official Python library for the hubmap-search-sdk API
|
5
5
|
Project-URL: Homepage, https://github.com/hubmapconsortium/search-python-sdk
|
6
6
|
Project-URL: Repository, https://github.com/hubmapconsortium/search-python-sdk
|
@@ -27,11 +27,14 @@ Requires-Dist: httpx<1,>=0.23.0
|
|
27
27
|
Requires-Dist: pydantic<3,>=1.9.0
|
28
28
|
Requires-Dist: sniffio
|
29
29
|
Requires-Dist: typing-extensions<5,>=4.10
|
30
|
+
Provides-Extra: aiohttp
|
31
|
+
Requires-Dist: aiohttp; extra == 'aiohttp'
|
32
|
+
Requires-Dist: httpx-aiohttp>=0.1.6; extra == 'aiohttp'
|
30
33
|
Description-Content-Type: text/markdown
|
31
34
|
|
32
35
|
# HuBMAP Search SDK Python API Library
|
33
36
|
|
34
|
-
[](https://pypi.org/project/hubmap_search_sdk/)
|
37
|
+
[>)](https://pypi.org/project/hubmap_search_sdk/)
|
35
38
|
|
36
39
|
The HuBMAP Search SDK Python library provides convenient access to the HuBMAP Search REST API from any Python 3.8+
|
37
40
|
application. The library includes type definitions for all request params and response fields,
|
@@ -88,6 +91,37 @@ asyncio.run(main())
|
|
88
91
|
|
89
92
|
Functionality between the synchronous and asynchronous clients is otherwise identical.
|
90
93
|
|
94
|
+
### With aiohttp
|
95
|
+
|
96
|
+
By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
|
97
|
+
|
98
|
+
You can enable this by installing `aiohttp`:
|
99
|
+
|
100
|
+
```sh
|
101
|
+
# install from PyPI
|
102
|
+
pip install --pre hubmap_search_sdk[aiohttp]
|
103
|
+
```
|
104
|
+
|
105
|
+
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
|
106
|
+
|
107
|
+
```python
|
108
|
+
import asyncio
|
109
|
+
from hubmap_search_sdk import DefaultAioHttpClient
|
110
|
+
from hubmap_search_sdk import AsyncHubmapSearchSDK
|
111
|
+
|
112
|
+
|
113
|
+
async def main() -> None:
|
114
|
+
async with AsyncHubmapSearchSDK(
|
115
|
+
bearer_token="My Bearer Token",
|
116
|
+
http_client=DefaultAioHttpClient(),
|
117
|
+
) as client:
|
118
|
+
indices = await client.indices.list()
|
119
|
+
print(indices.indices)
|
120
|
+
|
121
|
+
|
122
|
+
asyncio.run(main())
|
123
|
+
```
|
124
|
+
|
91
125
|
## Using types
|
92
126
|
|
93
127
|
Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
|
@@ -162,7 +196,7 @@ client.with_options(max_retries=5).indices.list()
|
|
162
196
|
### Timeouts
|
163
197
|
|
164
198
|
By default requests time out after 1 minute. You can configure this with a `timeout` option,
|
165
|
-
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
|
199
|
+
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
|
166
200
|
|
167
201
|
```python
|
168
202
|
from hubmap_search_sdk import HubmapSearchSDK
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# HuBMAP Search SDK Python API Library
|
2
2
|
|
3
|
-
[](https://pypi.org/project/hubmap_search_sdk/)
|
3
|
+
[>)](https://pypi.org/project/hubmap_search_sdk/)
|
4
4
|
|
5
5
|
The HuBMAP Search SDK Python library provides convenient access to the HuBMAP Search REST API from any Python 3.8+
|
6
6
|
application. The library includes type definitions for all request params and response fields,
|
@@ -57,6 +57,37 @@ asyncio.run(main())
|
|
57
57
|
|
58
58
|
Functionality between the synchronous and asynchronous clients is otherwise identical.
|
59
59
|
|
60
|
+
### With aiohttp
|
61
|
+
|
62
|
+
By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
|
63
|
+
|
64
|
+
You can enable this by installing `aiohttp`:
|
65
|
+
|
66
|
+
```sh
|
67
|
+
# install from PyPI
|
68
|
+
pip install --pre hubmap_search_sdk[aiohttp]
|
69
|
+
```
|
70
|
+
|
71
|
+
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
|
72
|
+
|
73
|
+
```python
|
74
|
+
import asyncio
|
75
|
+
from hubmap_search_sdk import DefaultAioHttpClient
|
76
|
+
from hubmap_search_sdk import AsyncHubmapSearchSDK
|
77
|
+
|
78
|
+
|
79
|
+
async def main() -> None:
|
80
|
+
async with AsyncHubmapSearchSDK(
|
81
|
+
bearer_token="My Bearer Token",
|
82
|
+
http_client=DefaultAioHttpClient(),
|
83
|
+
) as client:
|
84
|
+
indices = await client.indices.list()
|
85
|
+
print(indices.indices)
|
86
|
+
|
87
|
+
|
88
|
+
asyncio.run(main())
|
89
|
+
```
|
90
|
+
|
60
91
|
## Using types
|
61
92
|
|
62
93
|
Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
|
@@ -131,7 +162,7 @@ client.with_options(max_retries=5).indices.list()
|
|
131
162
|
### Timeouts
|
132
163
|
|
133
164
|
By default requests time out after 1 minute. You can configure this with a `timeout` option,
|
134
|
-
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
|
165
|
+
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
|
135
166
|
|
136
167
|
```python
|
137
168
|
from hubmap_search_sdk import HubmapSearchSDK
|
@@ -3,7 +3,7 @@
|
|
3
3
|
errors=()
|
4
4
|
|
5
5
|
if [ -z "${PYPI_TOKEN}" ]; then
|
6
|
-
errors+=("The
|
6
|
+
errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.")
|
7
7
|
fi
|
8
8
|
|
9
9
|
lenErrors=${#errors[@]}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "hubmap_search_sdk"
|
3
|
-
version = "1.0.0-alpha.
|
3
|
+
version = "1.0.0-alpha.14"
|
4
4
|
description = "The official Python library for the hubmap-search-sdk API"
|
5
5
|
dynamic = ["readme"]
|
6
6
|
license = "MIT"
|
@@ -37,6 +37,8 @@ classifiers = [
|
|
37
37
|
Homepage = "https://github.com/hubmapconsortium/search-python-sdk"
|
38
38
|
Repository = "https://github.com/hubmapconsortium/search-python-sdk"
|
39
39
|
|
40
|
+
[project.optional-dependencies]
|
41
|
+
aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"]
|
40
42
|
|
41
43
|
[tool.rye]
|
42
44
|
managed = true
|
@@ -54,6 +56,7 @@ dev-dependencies = [
|
|
54
56
|
"importlib-metadata>=6.7.0",
|
55
57
|
"rich>=13.7.1",
|
56
58
|
"nest_asyncio==1.6.0",
|
59
|
+
"pytest-xdist>=3.6.1",
|
57
60
|
]
|
58
61
|
|
59
62
|
[tool.rye.scripts]
|
@@ -125,7 +128,7 @@ replacement = '[\1](https://github.com/hubmapconsortium/search-python-sdk/tree/m
|
|
125
128
|
|
126
129
|
[tool.pytest.ini_options]
|
127
130
|
testpaths = ["tests"]
|
128
|
-
addopts = "--tb=short"
|
131
|
+
addopts = "--tb=short -n auto"
|
129
132
|
xfail_strict = true
|
130
133
|
asyncio_mode = "auto"
|
131
134
|
asyncio_default_fixture_loop_scope = "session"
|
@@ -10,6 +10,13 @@
|
|
10
10
|
# universal: false
|
11
11
|
|
12
12
|
-e file:.
|
13
|
+
aiohappyeyeballs==2.6.1
|
14
|
+
# via aiohttp
|
15
|
+
aiohttp==3.12.8
|
16
|
+
# via httpx-aiohttp
|
17
|
+
# via hubmap-search-sdk
|
18
|
+
aiosignal==1.3.2
|
19
|
+
# via aiohttp
|
13
20
|
annotated-types==0.6.0
|
14
21
|
# via pydantic
|
15
22
|
anyio==4.4.0
|
@@ -17,6 +24,10 @@ anyio==4.4.0
|
|
17
24
|
# via hubmap-search-sdk
|
18
25
|
argcomplete==3.1.2
|
19
26
|
# via nox
|
27
|
+
async-timeout==5.0.1
|
28
|
+
# via aiohttp
|
29
|
+
attrs==25.3.0
|
30
|
+
# via aiohttp
|
20
31
|
certifi==2023.7.22
|
21
32
|
# via httpcore
|
22
33
|
# via httpx
|
@@ -30,18 +41,27 @@ distro==1.8.0
|
|
30
41
|
exceptiongroup==1.2.2
|
31
42
|
# via anyio
|
32
43
|
# via pytest
|
44
|
+
execnet==2.1.1
|
45
|
+
# via pytest-xdist
|
33
46
|
filelock==3.12.4
|
34
47
|
# via virtualenv
|
48
|
+
frozenlist==1.6.2
|
49
|
+
# via aiohttp
|
50
|
+
# via aiosignal
|
35
51
|
h11==0.14.0
|
36
52
|
# via httpcore
|
37
53
|
httpcore==1.0.2
|
38
54
|
# via httpx
|
39
55
|
httpx==0.28.1
|
56
|
+
# via httpx-aiohttp
|
40
57
|
# via hubmap-search-sdk
|
41
58
|
# via respx
|
59
|
+
httpx-aiohttp==0.1.6
|
60
|
+
# via hubmap-search-sdk
|
42
61
|
idna==3.4
|
43
62
|
# via anyio
|
44
63
|
# via httpx
|
64
|
+
# via yarl
|
45
65
|
importlib-metadata==7.0.0
|
46
66
|
iniconfig==2.0.0
|
47
67
|
# via pytest
|
@@ -49,6 +69,9 @@ markdown-it-py==3.0.0
|
|
49
69
|
# via rich
|
50
70
|
mdurl==0.1.2
|
51
71
|
# via markdown-it-py
|
72
|
+
multidict==6.4.4
|
73
|
+
# via aiohttp
|
74
|
+
# via yarl
|
52
75
|
mypy==1.14.1
|
53
76
|
mypy-extensions==1.0.0
|
54
77
|
# via mypy
|
@@ -63,6 +86,9 @@ platformdirs==3.11.0
|
|
63
86
|
# via virtualenv
|
64
87
|
pluggy==1.5.0
|
65
88
|
# via pytest
|
89
|
+
propcache==0.3.1
|
90
|
+
# via aiohttp
|
91
|
+
# via yarl
|
66
92
|
pydantic==2.10.3
|
67
93
|
# via hubmap-search-sdk
|
68
94
|
pydantic-core==2.27.1
|
@@ -72,7 +98,9 @@ pygments==2.18.0
|
|
72
98
|
pyright==1.1.399
|
73
99
|
pytest==8.3.3
|
74
100
|
# via pytest-asyncio
|
101
|
+
# via pytest-xdist
|
75
102
|
pytest-asyncio==0.24.0
|
103
|
+
pytest-xdist==3.7.0
|
76
104
|
python-dateutil==2.8.2
|
77
105
|
# via time-machine
|
78
106
|
pytz==2023.3.post1
|
@@ -94,11 +122,14 @@ tomli==2.0.2
|
|
94
122
|
typing-extensions==4.12.2
|
95
123
|
# via anyio
|
96
124
|
# via hubmap-search-sdk
|
125
|
+
# via multidict
|
97
126
|
# via mypy
|
98
127
|
# via pydantic
|
99
128
|
# via pydantic-core
|
100
129
|
# via pyright
|
101
130
|
virtualenv==20.24.5
|
102
131
|
# via nox
|
132
|
+
yarl==1.20.0
|
133
|
+
# via aiohttp
|
103
134
|
zipp==3.17.0
|
104
135
|
# via importlib-metadata
|
@@ -10,11 +10,22 @@
|
|
10
10
|
# universal: false
|
11
11
|
|
12
12
|
-e file:.
|
13
|
+
aiohappyeyeballs==2.6.1
|
14
|
+
# via aiohttp
|
15
|
+
aiohttp==3.12.8
|
16
|
+
# via httpx-aiohttp
|
17
|
+
# via hubmap-search-sdk
|
18
|
+
aiosignal==1.3.2
|
19
|
+
# via aiohttp
|
13
20
|
annotated-types==0.6.0
|
14
21
|
# via pydantic
|
15
22
|
anyio==4.4.0
|
16
23
|
# via httpx
|
17
24
|
# via hubmap-search-sdk
|
25
|
+
async-timeout==5.0.1
|
26
|
+
# via aiohttp
|
27
|
+
attrs==25.3.0
|
28
|
+
# via aiohttp
|
18
29
|
certifi==2023.7.22
|
19
30
|
# via httpcore
|
20
31
|
# via httpx
|
@@ -22,15 +33,28 @@ distro==1.8.0
|
|
22
33
|
# via hubmap-search-sdk
|
23
34
|
exceptiongroup==1.2.2
|
24
35
|
# via anyio
|
36
|
+
frozenlist==1.6.2
|
37
|
+
# via aiohttp
|
38
|
+
# via aiosignal
|
25
39
|
h11==0.14.0
|
26
40
|
# via httpcore
|
27
41
|
httpcore==1.0.2
|
28
42
|
# via httpx
|
29
43
|
httpx==0.28.1
|
44
|
+
# via httpx-aiohttp
|
45
|
+
# via hubmap-search-sdk
|
46
|
+
httpx-aiohttp==0.1.6
|
30
47
|
# via hubmap-search-sdk
|
31
48
|
idna==3.4
|
32
49
|
# via anyio
|
33
50
|
# via httpx
|
51
|
+
# via yarl
|
52
|
+
multidict==6.4.4
|
53
|
+
# via aiohttp
|
54
|
+
# via yarl
|
55
|
+
propcache==0.3.1
|
56
|
+
# via aiohttp
|
57
|
+
# via yarl
|
34
58
|
pydantic==2.10.3
|
35
59
|
# via hubmap-search-sdk
|
36
60
|
pydantic-core==2.27.1
|
@@ -41,5 +65,8 @@ sniffio==1.3.0
|
|
41
65
|
typing-extensions==4.12.2
|
42
66
|
# via anyio
|
43
67
|
# via hubmap-search-sdk
|
68
|
+
# via multidict
|
44
69
|
# via pydantic
|
45
70
|
# via pydantic-core
|
71
|
+
yarl==1.20.0
|
72
|
+
# via aiohttp
|
@@ -36,7 +36,7 @@ from ._exceptions import (
|
|
36
36
|
UnprocessableEntityError,
|
37
37
|
APIResponseValidationError,
|
38
38
|
)
|
39
|
-
from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient
|
39
|
+
from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
|
40
40
|
from ._utils._logs import setup_logging as _setup_logging
|
41
41
|
|
42
42
|
__all__ = [
|
@@ -78,6 +78,7 @@ __all__ = [
|
|
78
78
|
"DEFAULT_CONNECTION_LIMITS",
|
79
79
|
"DefaultHttpxClient",
|
80
80
|
"DefaultAsyncHttpxClient",
|
81
|
+
"DefaultAioHttpClient",
|
81
82
|
]
|
82
83
|
|
83
84
|
if not _t.TYPE_CHECKING:
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_base_client.py
RENAMED
@@ -963,6 +963,9 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
|
|
963
963
|
if self.custom_auth is not None:
|
964
964
|
kwargs["auth"] = self.custom_auth
|
965
965
|
|
966
|
+
if options.follow_redirects is not None:
|
967
|
+
kwargs["follow_redirects"] = options.follow_redirects
|
968
|
+
|
966
969
|
log.debug("Sending HTTP Request: %s %s", request.method, request.url)
|
967
970
|
|
968
971
|
response = None
|
@@ -1080,7 +1083,14 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
|
|
1080
1083
|
) -> ResponseT:
|
1081
1084
|
origin = get_origin(cast_to) or cast_to
|
1082
1085
|
|
1083
|
-
if
|
1086
|
+
if (
|
1087
|
+
inspect.isclass(origin)
|
1088
|
+
and issubclass(origin, BaseAPIResponse)
|
1089
|
+
# we only want to actually return the custom BaseAPIResponse class if we're
|
1090
|
+
# returning the raw response, or if we're not streaming SSE, as if we're streaming
|
1091
|
+
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
|
1092
|
+
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
|
1093
|
+
):
|
1084
1094
|
if not issubclass(origin, APIResponse):
|
1085
1095
|
raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
|
1086
1096
|
|
@@ -1291,6 +1301,24 @@ class _DefaultAsyncHttpxClient(httpx.AsyncClient):
|
|
1291
1301
|
super().__init__(**kwargs)
|
1292
1302
|
|
1293
1303
|
|
1304
|
+
try:
|
1305
|
+
import httpx_aiohttp
|
1306
|
+
except ImportError:
|
1307
|
+
|
1308
|
+
class _DefaultAioHttpClient(httpx.AsyncClient):
|
1309
|
+
def __init__(self, **_kwargs: Any) -> None:
|
1310
|
+
raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
|
1311
|
+
else:
|
1312
|
+
|
1313
|
+
class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
|
1314
|
+
def __init__(self, **kwargs: Any) -> None:
|
1315
|
+
kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
|
1316
|
+
kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
|
1317
|
+
kwargs.setdefault("follow_redirects", True)
|
1318
|
+
|
1319
|
+
super().__init__(**kwargs)
|
1320
|
+
|
1321
|
+
|
1294
1322
|
if TYPE_CHECKING:
|
1295
1323
|
DefaultAsyncHttpxClient = httpx.AsyncClient
|
1296
1324
|
"""An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
|
@@ -1299,8 +1327,12 @@ if TYPE_CHECKING:
|
|
1299
1327
|
This is useful because overriding the `http_client` with your own instance of
|
1300
1328
|
`httpx.AsyncClient` will result in httpx's defaults being used, not ours.
|
1301
1329
|
"""
|
1330
|
+
|
1331
|
+
DefaultAioHttpClient = httpx.AsyncClient
|
1332
|
+
"""An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
|
1302
1333
|
else:
|
1303
1334
|
DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
|
1335
|
+
DefaultAioHttpClient = _DefaultAioHttpClient
|
1304
1336
|
|
1305
1337
|
|
1306
1338
|
class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
|
@@ -1472,6 +1504,9 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
|
|
1472
1504
|
if self.custom_auth is not None:
|
1473
1505
|
kwargs["auth"] = self.custom_auth
|
1474
1506
|
|
1507
|
+
if options.follow_redirects is not None:
|
1508
|
+
kwargs["follow_redirects"] = options.follow_redirects
|
1509
|
+
|
1475
1510
|
log.debug("Sending HTTP Request: %s %s", request.method, request.url)
|
1476
1511
|
|
1477
1512
|
response = None
|
@@ -1580,7 +1615,14 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
|
|
1580
1615
|
) -> ResponseT:
|
1581
1616
|
origin = get_origin(cast_to) or cast_to
|
1582
1617
|
|
1583
|
-
if
|
1618
|
+
if (
|
1619
|
+
inspect.isclass(origin)
|
1620
|
+
and issubclass(origin, BaseAPIResponse)
|
1621
|
+
# we only want to actually return the custom BaseAPIResponse class if we're
|
1622
|
+
# returning the raw response, or if we're not streaming SSE, as if we're streaming
|
1623
|
+
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
|
1624
|
+
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
|
1625
|
+
):
|
1584
1626
|
if not issubclass(origin, AsyncAPIResponse):
|
1585
1627
|
raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
|
1586
1628
|
|
@@ -737,6 +737,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
|
|
737
737
|
idempotency_key: str
|
738
738
|
json_data: Body
|
739
739
|
extra_json: AnyMapping
|
740
|
+
follow_redirects: bool
|
740
741
|
|
741
742
|
|
742
743
|
@final
|
@@ -750,6 +751,7 @@ class FinalRequestOptions(pydantic.BaseModel):
|
|
750
751
|
files: Union[HttpxRequestFiles, None] = None
|
751
752
|
idempotency_key: Union[str, None] = None
|
752
753
|
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
|
754
|
+
follow_redirects: Union[bool, None] = None
|
753
755
|
|
754
756
|
# It should be noted that we cannot use `json` here as that would override
|
755
757
|
# a BaseModel method in an incompatible fashion.
|
@@ -100,6 +100,7 @@ class RequestOptions(TypedDict, total=False):
|
|
100
100
|
params: Query
|
101
101
|
extra_json: AnyMapping
|
102
102
|
idempotency_key: str
|
103
|
+
follow_redirects: bool
|
103
104
|
|
104
105
|
|
105
106
|
# Sentinel class used until PEP 0661 is accepted
|
@@ -215,3 +216,4 @@ class _GenericAlias(Protocol):
|
|
215
216
|
|
216
217
|
class HttpxSendArgs(TypedDict, total=False):
|
217
218
|
auth: httpx.Auth
|
219
|
+
follow_redirects: bool
|
@@ -880,7 +880,9 @@ class TestAdd:
|
|
880
880
|
|
881
881
|
|
882
882
|
class TestAsyncAdd:
|
883
|
-
parametrize = pytest.mark.parametrize(
|
883
|
+
parametrize = pytest.mark.parametrize(
|
884
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
885
|
+
)
|
884
886
|
|
885
887
|
@pytest.mark.skip()
|
886
888
|
@parametrize
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_clear_docs.py
RENAMED
@@ -175,7 +175,9 @@ class TestClearDocs:
|
|
175
175
|
|
176
176
|
|
177
177
|
class TestAsyncClearDocs:
|
178
|
-
parametrize = pytest.mark.parametrize(
|
178
|
+
parametrize = pytest.mark.parametrize(
|
179
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
180
|
+
)
|
179
181
|
|
180
182
|
@pytest.mark.skip()
|
181
183
|
@parametrize
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_indices.py
RENAMED
@@ -47,7 +47,9 @@ class TestIndices:
|
|
47
47
|
|
48
48
|
|
49
49
|
class TestAsyncIndices:
|
50
|
-
parametrize = pytest.mark.parametrize(
|
50
|
+
parametrize = pytest.mark.parametrize(
|
51
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
52
|
+
)
|
51
53
|
|
52
54
|
@pytest.mark.skip()
|
53
55
|
@parametrize
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_mapping.py
RENAMED
@@ -88,7 +88,9 @@ class TestMapping:
|
|
88
88
|
|
89
89
|
|
90
90
|
class TestAsyncMapping:
|
91
|
-
parametrize = pytest.mark.parametrize(
|
91
|
+
parametrize = pytest.mark.parametrize(
|
92
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
93
|
+
)
|
92
94
|
|
93
95
|
@pytest.mark.skip()
|
94
96
|
@parametrize
|
@@ -100,7 +100,9 @@ class TestMget:
|
|
100
100
|
|
101
101
|
|
102
102
|
class TestAsyncMget:
|
103
|
-
parametrize = pytest.mark.parametrize(
|
103
|
+
parametrize = pytest.mark.parametrize(
|
104
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
105
|
+
)
|
104
106
|
|
105
107
|
@pytest.mark.skip()
|
106
108
|
@parametrize
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_param_search.py
RENAMED
@@ -69,7 +69,9 @@ class TestParamSearch:
|
|
69
69
|
|
70
70
|
|
71
71
|
class TestAsyncParamSearch:
|
72
|
-
parametrize = pytest.mark.parametrize(
|
72
|
+
parametrize = pytest.mark.parametrize(
|
73
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
74
|
+
)
|
73
75
|
|
74
76
|
@pytest.mark.skip()
|
75
77
|
@parametrize
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_reindex.py
RENAMED
@@ -59,7 +59,9 @@ class TestReindex:
|
|
59
59
|
|
60
60
|
|
61
61
|
class TestAsyncReindex:
|
62
|
-
parametrize = pytest.mark.parametrize(
|
62
|
+
parametrize = pytest.mark.parametrize(
|
63
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
64
|
+
)
|
63
65
|
|
64
66
|
@pytest.mark.skip()
|
65
67
|
@parametrize
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_scroll_search.py
RENAMED
@@ -75,7 +75,9 @@ class TestScrollSearch:
|
|
75
75
|
|
76
76
|
|
77
77
|
class TestAsyncScrollSearch:
|
78
|
-
parametrize = pytest.mark.parametrize(
|
78
|
+
parametrize = pytest.mark.parametrize(
|
79
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
80
|
+
)
|
79
81
|
|
80
82
|
@pytest.mark.skip()
|
81
83
|
@parametrize
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_search.py
RENAMED
@@ -180,7 +180,9 @@ class TestSearch:
|
|
180
180
|
|
181
181
|
|
182
182
|
class TestAsyncSearch:
|
183
|
-
parametrize = pytest.mark.parametrize(
|
183
|
+
parametrize = pytest.mark.parametrize(
|
184
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
185
|
+
)
|
184
186
|
|
185
187
|
@pytest.mark.skip()
|
186
188
|
@parametrize
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/tests/api_resources/test_update.py
RENAMED
@@ -880,7 +880,9 @@ class TestUpdate:
|
|
880
880
|
|
881
881
|
|
882
882
|
class TestAsyncUpdate:
|
883
|
-
parametrize = pytest.mark.parametrize(
|
883
|
+
parametrize = pytest.mark.parametrize(
|
884
|
+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
885
|
+
)
|
884
886
|
|
885
887
|
@pytest.mark.skip()
|
886
888
|
@parametrize
|
@@ -1,13 +1,17 @@
|
|
1
|
+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
2
|
+
|
1
3
|
from __future__ import annotations
|
2
4
|
|
3
5
|
import os
|
4
6
|
import logging
|
5
7
|
from typing import TYPE_CHECKING, Iterator, AsyncIterator
|
6
8
|
|
9
|
+
import httpx
|
7
10
|
import pytest
|
8
11
|
from pytest_asyncio import is_async_test
|
9
12
|
|
10
|
-
from hubmap_search_sdk import HubmapSearchSDK, AsyncHubmapSearchSDK
|
13
|
+
from hubmap_search_sdk import HubmapSearchSDK, AsyncHubmapSearchSDK, DefaultAioHttpClient
|
14
|
+
from hubmap_search_sdk._utils import is_dict
|
11
15
|
|
12
16
|
if TYPE_CHECKING:
|
13
17
|
from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage]
|
@@ -25,6 +29,19 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None:
|
|
25
29
|
for async_test in pytest_asyncio_tests:
|
26
30
|
async_test.add_marker(session_scope_marker, append=False)
|
27
31
|
|
32
|
+
# We skip tests that use both the aiohttp client and respx_mock as respx_mock
|
33
|
+
# doesn't support custom transports.
|
34
|
+
for item in items:
|
35
|
+
if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames:
|
36
|
+
continue
|
37
|
+
|
38
|
+
if not hasattr(item, "callspec"):
|
39
|
+
continue
|
40
|
+
|
41
|
+
async_client_param = item.callspec.params.get("async_client")
|
42
|
+
if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp":
|
43
|
+
item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock"))
|
44
|
+
|
28
45
|
|
29
46
|
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
|
30
47
|
|
@@ -43,11 +60,25 @@ def client(request: FixtureRequest) -> Iterator[HubmapSearchSDK]:
|
|
43
60
|
|
44
61
|
@pytest.fixture(scope="session")
|
45
62
|
async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncHubmapSearchSDK]:
|
46
|
-
|
47
|
-
|
48
|
-
|
63
|
+
param = getattr(request, "param", True)
|
64
|
+
|
65
|
+
# defaults
|
66
|
+
strict = True
|
67
|
+
http_client: None | httpx.AsyncClient = None
|
68
|
+
|
69
|
+
if isinstance(param, bool):
|
70
|
+
strict = param
|
71
|
+
elif is_dict(param):
|
72
|
+
strict = param.get("strict", True)
|
73
|
+
assert isinstance(strict, bool)
|
74
|
+
|
75
|
+
http_client_type = param.get("http_client", "httpx")
|
76
|
+
if http_client_type == "aiohttp":
|
77
|
+
http_client = DefaultAioHttpClient()
|
78
|
+
else:
|
79
|
+
raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict")
|
49
80
|
|
50
81
|
async with AsyncHubmapSearchSDK(
|
51
|
-
base_url=base_url, bearer_token=bearer_token, _strict_response_validation=strict
|
82
|
+
base_url=base_url, bearer_token=bearer_token, _strict_response_validation=strict, http_client=http_client
|
52
83
|
) as client:
|
53
84
|
yield client
|
@@ -24,12 +24,13 @@ from pydantic import ValidationError
|
|
24
24
|
from hubmap_search_sdk import HubmapSearchSDK, AsyncHubmapSearchSDK, APIResponseValidationError
|
25
25
|
from hubmap_search_sdk._types import Omit
|
26
26
|
from hubmap_search_sdk._models import BaseModel, FinalRequestOptions
|
27
|
-
from hubmap_search_sdk._constants import RAW_RESPONSE_HEADER
|
28
27
|
from hubmap_search_sdk._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError
|
29
28
|
from hubmap_search_sdk._base_client import (
|
30
29
|
DEFAULT_TIMEOUT,
|
31
30
|
HTTPX_DEFAULT_TIMEOUT,
|
32
31
|
BaseClient,
|
32
|
+
DefaultHttpxClient,
|
33
|
+
DefaultAsyncHttpxClient,
|
33
34
|
make_request_options,
|
34
35
|
)
|
35
36
|
|
@@ -193,6 +194,7 @@ class TestHubmapSearchSDK:
|
|
193
194
|
copy_param = copy_signature.parameters.get(name)
|
194
195
|
assert copy_param is not None, f"copy() signature is missing the {name} param"
|
195
196
|
|
197
|
+
@pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12")
|
196
198
|
def test_copy_build_request(self) -> None:
|
197
199
|
options = FinalRequestOptions(method="get", url="/foo")
|
198
200
|
|
@@ -738,22 +740,21 @@ class TestHubmapSearchSDK:
|
|
738
740
|
|
739
741
|
@mock.patch("hubmap_search_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
|
740
742
|
@pytest.mark.respx(base_url=base_url)
|
741
|
-
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
|
743
|
+
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: HubmapSearchSDK) -> None:
|
742
744
|
respx_mock.get("/indices").mock(side_effect=httpx.TimeoutException("Test timeout error"))
|
743
745
|
|
744
746
|
with pytest.raises(APITimeoutError):
|
745
|
-
|
747
|
+
client.indices.with_streaming_response.list().__enter__()
|
746
748
|
|
747
749
|
assert _get_open_connections(self.client) == 0
|
748
750
|
|
749
751
|
@mock.patch("hubmap_search_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
|
750
752
|
@pytest.mark.respx(base_url=base_url)
|
751
|
-
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
|
753
|
+
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: HubmapSearchSDK) -> None:
|
752
754
|
respx_mock.get("/indices").mock(return_value=httpx.Response(500))
|
753
755
|
|
754
756
|
with pytest.raises(APIStatusError):
|
755
|
-
|
756
|
-
|
757
|
+
client.indices.with_streaming_response.list().__enter__()
|
757
758
|
assert _get_open_connections(self.client) == 0
|
758
759
|
|
759
760
|
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
|
@@ -833,6 +834,55 @@ class TestHubmapSearchSDK:
|
|
833
834
|
|
834
835
|
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
|
835
836
|
|
837
|
+
def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
838
|
+
# Test that the proxy environment variables are set correctly
|
839
|
+
monkeypatch.setenv("HTTPS_PROXY", "https://example.org")
|
840
|
+
|
841
|
+
client = DefaultHttpxClient()
|
842
|
+
|
843
|
+
mounts = tuple(client._mounts.items())
|
844
|
+
assert len(mounts) == 1
|
845
|
+
assert mounts[0][0].pattern == "https://"
|
846
|
+
|
847
|
+
@pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning")
|
848
|
+
def test_default_client_creation(self) -> None:
|
849
|
+
# Ensure that the client can be initialized without any exceptions
|
850
|
+
DefaultHttpxClient(
|
851
|
+
verify=True,
|
852
|
+
cert=None,
|
853
|
+
trust_env=True,
|
854
|
+
http1=True,
|
855
|
+
http2=False,
|
856
|
+
limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
|
857
|
+
)
|
858
|
+
|
859
|
+
@pytest.mark.respx(base_url=base_url)
|
860
|
+
def test_follow_redirects(self, respx_mock: MockRouter) -> None:
|
861
|
+
# Test that the default follow_redirects=True allows following redirects
|
862
|
+
respx_mock.post("/redirect").mock(
|
863
|
+
return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"})
|
864
|
+
)
|
865
|
+
respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"}))
|
866
|
+
|
867
|
+
response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response)
|
868
|
+
assert response.status_code == 200
|
869
|
+
assert response.json() == {"status": "ok"}
|
870
|
+
|
871
|
+
@pytest.mark.respx(base_url=base_url)
|
872
|
+
def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None:
|
873
|
+
# Test that follow_redirects=False prevents following redirects
|
874
|
+
respx_mock.post("/redirect").mock(
|
875
|
+
return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"})
|
876
|
+
)
|
877
|
+
|
878
|
+
with pytest.raises(APIStatusError) as exc_info:
|
879
|
+
self.client.post(
|
880
|
+
"/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response
|
881
|
+
)
|
882
|
+
|
883
|
+
assert exc_info.value.response.status_code == 302
|
884
|
+
assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected"
|
885
|
+
|
836
886
|
|
837
887
|
class TestAsyncHubmapSearchSDK:
|
838
888
|
client = AsyncHubmapSearchSDK(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True)
|
@@ -972,6 +1022,7 @@ class TestAsyncHubmapSearchSDK:
|
|
972
1022
|
copy_param = copy_signature.parameters.get(name)
|
973
1023
|
assert copy_param is not None, f"copy() signature is missing the {name} param"
|
974
1024
|
|
1025
|
+
@pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12")
|
975
1026
|
def test_copy_build_request(self) -> None:
|
976
1027
|
options = FinalRequestOptions(method="get", url="/foo")
|
977
1028
|
|
@@ -1523,26 +1574,25 @@ class TestAsyncHubmapSearchSDK:
|
|
1523
1574
|
|
1524
1575
|
@mock.patch("hubmap_search_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
|
1525
1576
|
@pytest.mark.respx(base_url=base_url)
|
1526
|
-
async def test_retrying_timeout_errors_doesnt_leak(
|
1577
|
+
async def test_retrying_timeout_errors_doesnt_leak(
|
1578
|
+
self, respx_mock: MockRouter, async_client: AsyncHubmapSearchSDK
|
1579
|
+
) -> None:
|
1527
1580
|
respx_mock.get("/indices").mock(side_effect=httpx.TimeoutException("Test timeout error"))
|
1528
1581
|
|
1529
1582
|
with pytest.raises(APITimeoutError):
|
1530
|
-
await
|
1531
|
-
"/indices", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
|
1532
|
-
)
|
1583
|
+
await async_client.indices.with_streaming_response.list().__aenter__()
|
1533
1584
|
|
1534
1585
|
assert _get_open_connections(self.client) == 0
|
1535
1586
|
|
1536
1587
|
@mock.patch("hubmap_search_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
|
1537
1588
|
@pytest.mark.respx(base_url=base_url)
|
1538
|
-
async def test_retrying_status_errors_doesnt_leak(
|
1589
|
+
async def test_retrying_status_errors_doesnt_leak(
|
1590
|
+
self, respx_mock: MockRouter, async_client: AsyncHubmapSearchSDK
|
1591
|
+
) -> None:
|
1539
1592
|
respx_mock.get("/indices").mock(return_value=httpx.Response(500))
|
1540
1593
|
|
1541
1594
|
with pytest.raises(APIStatusError):
|
1542
|
-
await
|
1543
|
-
"/indices", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
|
1544
|
-
)
|
1545
|
-
|
1595
|
+
await async_client.indices.with_streaming_response.list().__aenter__()
|
1546
1596
|
assert _get_open_connections(self.client) == 0
|
1547
1597
|
|
1548
1598
|
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
|
@@ -1669,3 +1719,52 @@ class TestAsyncHubmapSearchSDK:
|
|
1669
1719
|
raise AssertionError("calling get_platform using asyncify resulted in a hung process")
|
1670
1720
|
|
1671
1721
|
time.sleep(0.1)
|
1722
|
+
|
1723
|
+
async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
1724
|
+
# Test that the proxy environment variables are set correctly
|
1725
|
+
monkeypatch.setenv("HTTPS_PROXY", "https://example.org")
|
1726
|
+
|
1727
|
+
client = DefaultAsyncHttpxClient()
|
1728
|
+
|
1729
|
+
mounts = tuple(client._mounts.items())
|
1730
|
+
assert len(mounts) == 1
|
1731
|
+
assert mounts[0][0].pattern == "https://"
|
1732
|
+
|
1733
|
+
@pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning")
|
1734
|
+
async def test_default_client_creation(self) -> None:
|
1735
|
+
# Ensure that the client can be initialized without any exceptions
|
1736
|
+
DefaultAsyncHttpxClient(
|
1737
|
+
verify=True,
|
1738
|
+
cert=None,
|
1739
|
+
trust_env=True,
|
1740
|
+
http1=True,
|
1741
|
+
http2=False,
|
1742
|
+
limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
|
1743
|
+
)
|
1744
|
+
|
1745
|
+
@pytest.mark.respx(base_url=base_url)
|
1746
|
+
async def test_follow_redirects(self, respx_mock: MockRouter) -> None:
|
1747
|
+
# Test that the default follow_redirects=True allows following redirects
|
1748
|
+
respx_mock.post("/redirect").mock(
|
1749
|
+
return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"})
|
1750
|
+
)
|
1751
|
+
respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"}))
|
1752
|
+
|
1753
|
+
response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response)
|
1754
|
+
assert response.status_code == 200
|
1755
|
+
assert response.json() == {"status": "ok"}
|
1756
|
+
|
1757
|
+
@pytest.mark.respx(base_url=base_url)
|
1758
|
+
async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None:
|
1759
|
+
# Test that follow_redirects=False prevents following redirects
|
1760
|
+
respx_mock.post("/redirect").mock(
|
1761
|
+
return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"})
|
1762
|
+
)
|
1763
|
+
|
1764
|
+
with pytest.raises(APIStatusError) as exc_info:
|
1765
|
+
await self.client.post(
|
1766
|
+
"/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response
|
1767
|
+
)
|
1768
|
+
|
1769
|
+
assert exc_info.value.response.status_code == 302
|
1770
|
+
assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_constants.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_exceptions.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_resource.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_response.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_streaming.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/__init__.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_logs.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_proxy.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_streams.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_sync.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_transform.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_typing.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/_utils/_utils.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/add.py
RENAMED
File without changes
|
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/indices.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/mapping.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/mget.py
RENAMED
File without changes
|
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/reindex.py
RENAMED
File without changes
|
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/search.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/resources/update.py
RENAMED
File without changes
|
{hubmap_search_sdk-1.0.0a12 → hubmap_search_sdk-1.0.0a14}/src/hubmap_search_sdk/types/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|