diff --git a/docs/reference/async.md b/docs/reference/async.md index 70e8949d5..b151150e3 100644 --- a/docs/reference/async.md +++ b/docs/reference/async.md @@ -50,6 +50,27 @@ All APIs that are available under the sync client are also available under the a See also the [Using OpenTelemetry](/reference/opentelemetry.md) page. +## Trio support + +If you prefer using Trio instead of asyncio to take advantage of its better structured concurrency support, you can use the HTTPX async node which supports Trio out of the box. + +```python +import trio +from elasticsearch import AsyncElasticsearch + +client = AsyncElasticsearch( + "https://...", + api_key="...", + node_class="httpxasync") + +async def main(): + resp = await client.info() + print(resp.body) + +trio.run(main) +``` + +The one limitation of Trio support is that it does not currently support node sniffing, which was not implemented with structured concurrency in mind. ## Frequently Asked Questions [_frequently_asked_questions] diff --git a/docs/reference/dsl_how_to_guides.md b/docs/reference/dsl_how_to_guides.md index 5f0884c3c..66137c1ff 100644 --- a/docs/reference/dsl_how_to_guides.md +++ b/docs/reference/dsl_how_to_guides.md @@ -1555,6 +1555,12 @@ The DSL module supports async/await with [asyncio](https://docs.python.org/3/lib $ python -m pip install "elasticsearch[async]" ``` +The DSL module also supports [Trio](https://trio.readthedocs.io/en/stable/) when using the Async HTTPX client. You do need to install Trio and HTTPX separately: + +```bash +$ python -m pip install "elasticsearch trio httpx" +``` + ### Connections [_connections] Use the `async_connections` module to manage your asynchronous connections. @@ -1565,6 +1571,14 @@ from elasticsearch.dsl import async_connections async_connections.create_connection(hosts=['localhost'], timeout=20) ``` +If you're using Trio, you need to explicitly request the Async HTTP client: + +```python +from elasticsearch.dsl import async_connections + +async_connections.create_connection(hosts=['localhost'], node_class="httpxasync") +``` + All the options available in the `connections` module can be used with `async_connections`. #### How to avoid *Unclosed client session / connector* warnings on exit [_how_to_avoid_unclosed_client_session_connector_warnings_on_exit] @@ -1576,8 +1590,6 @@ es = async_connections.get_connection() await es.close() ``` - - ### Search DSL [_search_dsl] Use the `AsyncSearch` class to perform asynchronous searches. diff --git a/elasticsearch/_async/helpers.py b/elasticsearch/_async/helpers.py index e4d5e6bc5..6775561f6 100644 --- a/elasticsearch/_async/helpers.py +++ b/elasticsearch/_async/helpers.py @@ -33,6 +33,8 @@ Union, ) +import sniffio + from ..exceptions import ApiError, NotFoundError, TransportError from ..helpers.actions import ( _TYPE_BULK_ACTION, @@ -53,6 +55,15 @@ T = TypeVar("T") +async def _sleep(seconds: float) -> None: + if sniffio.current_async_library() == "trio": + import trio + + await trio.sleep(seconds) + else: + await asyncio.sleep(seconds) + + async def _chunk_actions( actions: AsyncIterable[_TYPE_BULK_ACTION_HEADER_AND_BODY], chunk_size: int, @@ -245,9 +256,7 @@ async def map_actions() -> AsyncIterable[_TYPE_BULK_ACTION_HEADER_AND_BODY]: ] ] = [] if attempt: - await asyncio.sleep( - min(max_backoff, initial_backoff * 2 ** (attempt - 1)) - ) + await _sleep(min(max_backoff, initial_backoff * 2 ** (attempt - 1))) try: data: Union[ diff --git a/pyproject.toml b/pyproject.toml index a8e5ead9e..4308b0508 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,11 +41,17 @@ keywords = [ ] dynamic = ["version"] dependencies = [ - "elastic-transport>=9.1.0,<10", + # TODO revert before merging/releasing + "elastic-transport @ git+https://github.com/pquentin/elastic-transport-python.git@trio-support", "python-dateutil", "typing-extensions", + "sniffio", ] +# TODO revert before merging/releasing +[tool.hatch.metadata] +allow-direct-references = true + [project.optional-dependencies] async = ["aiohttp>=3,<4"] requests = ["requests>=2.4.0, !=2.32.2, <3.0.0"] @@ -56,6 +62,7 @@ vectorstore_mmr = ["numpy>=1", "simsimd>=3"] dev = [ "requests>=2, <3", "aiohttp", + "httpx", "pytest", "pytest-cov", "pytest-mock", @@ -78,6 +85,8 @@ dev = [ "mapbox-vector-tile", "jinja2", "tqdm", + "trio", + "anyio", "mypy", "pyright", "types-python-dateutil", diff --git a/test_elasticsearch/test_async/test_server/conftest.py b/test_elasticsearch/test_async/test_server/conftest.py index 623646e7d..c0baad2e2 100644 --- a/test_elasticsearch/test_async/test_server/conftest.py +++ b/test_elasticsearch/test_async/test_server/conftest.py @@ -16,27 +16,27 @@ # under the License. import pytest -import pytest_asyncio +import sniffio import elasticsearch from ...utils import CA_CERTS, wipe_cluster -pytestmark = pytest.mark.asyncio - -@pytest_asyncio.fixture(scope="function") +@pytest.fixture(scope="function") async def async_client_factory(elasticsearch_url): - - if not hasattr(elasticsearch, "AsyncElasticsearch"): - pytest.skip("test requires 'AsyncElasticsearch' and aiohttp to be installed") - + print("async!", elasticsearch_url) + kwargs = {} + if sniffio.current_async_library() == "trio": + kwargs["node_class"] = "httpxasync" # Unfortunately the asyncio client needs to be rebuilt every # test execution due to how pytest-asyncio manages # event loops (one per test!) client = None try: - client = elasticsearch.AsyncElasticsearch(elasticsearch_url, ca_certs=CA_CERTS) + client = elasticsearch.AsyncElasticsearch( + elasticsearch_url, ca_certs=CA_CERTS, **kwargs + ) yield client finally: if client: diff --git a/test_elasticsearch/test_async/test_server/test_clients.py b/test_elasticsearch/test_async/test_server/test_clients.py index 00de2c7fb..eace5290f 100644 --- a/test_elasticsearch/test_async/test_server/test_clients.py +++ b/test_elasticsearch/test_async/test_server/test_clients.py @@ -18,7 +18,7 @@ import pytest -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.anyio @pytest.mark.parametrize("kwargs", [{"body": {"text": "привет"}}, {"text": "привет"}]) diff --git a/test_elasticsearch/test_async/test_server/test_helpers.py b/test_elasticsearch/test_async/test_server/test_helpers.py index a235784be..628920ca5 100644 --- a/test_elasticsearch/test_async/test_server/test_helpers.py +++ b/test_elasticsearch/test_async/test_server/test_helpers.py @@ -15,20 +15,19 @@ # specific language governing permissions and limitations # under the License. -import asyncio import logging from datetime import datetime, timedelta, timezone from unittest.mock import MagicMock, call, patch +import anyio import pytest -import pytest_asyncio from elastic_transport import ApiResponseMeta, ObjectApiResponse from elasticsearch import helpers from elasticsearch.exceptions import ApiError from elasticsearch.helpers import ScanError -pytestmark = [pytest.mark.asyncio] +pytestmark = pytest.mark.anyio class AsyncMock(MagicMock): @@ -92,7 +91,7 @@ async def test_all_documents_get_inserted(self, async_client): async def test_documents_data_types(self, async_client): async def async_gen(): for x in range(100): - await asyncio.sleep(0) + await anyio.sleep(0) yield {"answer": x, "_id": x} def sync_gen(): @@ -491,7 +490,7 @@ def __await__(self): return self().__await__() -@pytest_asyncio.fixture(scope="function") +@pytest.fixture(scope="function") async def scan_teardown(async_client): yield await async_client.clear_scroll(scroll_id="_all") @@ -915,7 +914,7 @@ async def test_scan_from_keyword_is_aliased(async_client, scan_kwargs): assert "from" not in search_mock.call_args[1] -@pytest_asyncio.fixture(scope="function") +@pytest.fixture(scope="function") async def reindex_setup(async_client): bulk = [] for x in range(100): @@ -993,7 +992,7 @@ async def test_all_documents_get_moved(self, async_client, reindex_setup): )["_source"] -@pytest_asyncio.fixture(scope="function") +@pytest.fixture(scope="function") async def parent_reindex_setup(async_client): body = { "settings": {"number_of_shards": 1, "number_of_replicas": 0}, @@ -1054,7 +1053,7 @@ async def test_children_are_reindexed_correctly( } == q -@pytest_asyncio.fixture(scope="function") +@pytest.fixture(scope="function") async def reindex_data_stream_setup(async_client): dt = datetime.now(tz=timezone.utc) bulk = [] diff --git a/test_elasticsearch/test_async/test_server/test_mapbox_vector_tile.py b/test_elasticsearch/test_async/test_server/test_mapbox_vector_tile.py index 4f5dcaec4..94b5eabe0 100644 --- a/test_elasticsearch/test_async/test_server/test_mapbox_vector_tile.py +++ b/test_elasticsearch/test_async/test_server/test_mapbox_vector_tile.py @@ -16,14 +16,13 @@ # under the License. import pytest -import pytest_asyncio from elasticsearch import RequestError -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.anyio -@pytest_asyncio.fixture(scope="function") +@pytest.fixture(scope="function") async def mvt_setup(async_client): await async_client.indices.create( index="museums", diff --git a/test_elasticsearch/test_async/test_server/test_rest_api_spec.py b/test_elasticsearch/test_async/test_server/test_rest_api_spec.py index c48262b61..ee148c0cd 100644 --- a/test_elasticsearch/test_async/test_server/test_rest_api_spec.py +++ b/test_elasticsearch/test_async/test_server/test_rest_api_spec.py @@ -25,7 +25,6 @@ import warnings import pytest -import pytest_asyncio from elasticsearch import ElasticsearchWarning, RequestError @@ -39,6 +38,8 @@ ) from ...utils import parse_version +# We're not using `pytest.mark.anyio` here because it would run the test suite twice, +# which does not work as it does not fully clean up after itself. pytestmark = pytest.mark.asyncio XPACK_FEATURES = None @@ -240,7 +241,7 @@ async def _feature_enabled(self, name): return name in XPACK_FEATURES -@pytest_asyncio.fixture(scope="function") +@pytest.fixture(scope="function") def async_runner(async_client_factory): return AsyncYamlRunner(async_client_factory) diff --git a/test_elasticsearch/test_async/test_transport.py b/test_elasticsearch/test_async/test_transport.py index cf9b8600a..e17a446a9 100644 --- a/test_elasticsearch/test_async/test_transport.py +++ b/test_elasticsearch/test_async/test_transport.py @@ -16,11 +16,12 @@ # under the License. -import asyncio import re +import time import warnings from typing import Any, Dict, Optional +import anyio import pytest from elastic_transport import ( ApiResponseMeta, @@ -40,8 +41,6 @@ UnsupportedProductError, ) -pytestmark = pytest.mark.asyncio - class DummyNode(BaseAsyncNode): def __init__(self, config: NodeConfig): @@ -175,6 +174,7 @@ def mark_live(self, connection): }""" +@pytest.mark.anyio class TestTransport: async def test_request_timeout_extracted_from_params_and_passed(self): client = AsyncElasticsearch( @@ -378,6 +378,9 @@ async def test_override_mark_dead_mark_live(self): assert len(client.transport.node_pool._alive_nodes) == 2 assert len(client.transport.node_pool._dead_consecutive_failures) == 0 + +@pytest.mark.asyncio +class TestSniffing: @pytest.mark.parametrize( ["nodes_info_response", "node_host"], [(CLUSTER_NODES, "1.1.1.1"), (CLUSTER_NODES_7x_PUBLISH_HOST, "somehost.tld")], @@ -528,23 +531,22 @@ async def test_sniff_on_node_failure_triggers(self, extra_key, extra_value): assert len(client.transport.node_pool) == 3 async def test_sniff_after_n_seconds(self): - event_loop = asyncio.get_running_loop() client = AsyncElasticsearch( # noqa: F821 [NodeConfig("http", "localhost", 9200, _extras={"data": CLUSTER_NODES})], node_class=DummyNode, min_delay_between_sniffing=5, ) - client.transport._last_sniffed_at = event_loop.time() + client.transport._last_sniffed_at = time.monotonic() await client.info() for _ in range(4): await client.info() - await asyncio.sleep(0) + await anyio.sleep(0) assert 1 == len(client.transport.node_pool) - client.transport._last_sniffed_at = event_loop.time() - 5.1 + client.transport._last_sniffed_at = time.monotonic() - 5.1 await client.info() await client.transport._sniffing_task # Need to wait for the sniffing task to complete @@ -554,9 +556,9 @@ async def test_sniff_after_n_seconds(self): node.base_url for node in client.transport.node_pool.all() ) assert ( - event_loop.time() - 1 + time.monotonic() - 1 < client.transport._last_sniffed_at - < event_loop.time() + 0.01 + < time.monotonic() + 0.01 ) @pytest.mark.parametrize( @@ -580,8 +582,10 @@ async def test_sniffing_disabled_on_elastic_cloud(self, kwargs): == "Sniffing should not be enabled when connecting to Elastic Cloud" ) - async def test_sniff_on_start_close_unlocks_async_calls(self): - event_loop = asyncio.get_running_loop() + async def test_sniff_on_start_close_unlocks_async_calls(self, anyio_backend): + if anyio_backend == "trio": + pytest.skip("trio does not support sniffing") + client = AsyncElasticsearch( # noqa: F821 [ NodeConfig( @@ -596,20 +600,17 @@ async def test_sniff_on_start_close_unlocks_async_calls(self): ) # Start making _async_calls() before we cancel - tasks = [] - start_time = event_loop.time() - for _ in range(3): - tasks.append(event_loop.create_task(client.info())) - await asyncio.sleep(0) - - # Close the transport while the sniffing task is active! :( - await client.transport.close() - - # Now we start waiting on all those _async_calls() - await asyncio.gather(*tasks) - end_time = event_loop.time() - duration = end_time - start_time + async with anyio.create_task_group() as tg: + start_time = time.monotonic() + for _ in range(3): + tg.start_soon(client.info) + await anyio.sleep(0) + + # Close the transport while the sniffing task is active! :( + await client.transport.close() + end_time = time.monotonic() + duration = end_time - start_time # A lot quicker than 10 seconds defined in 'delay' assert duration < 1 @@ -661,6 +662,7 @@ def sniffed_node_callback( assert ports == {9200, 124} +@pytest.mark.anyio @pytest.mark.parametrize("headers", [{}, {"X-elastic-product": "BAD HEADER"}]) async def test_unsupported_product_error(headers): client = AsyncElasticsearch( @@ -690,6 +692,7 @@ async def test_unsupported_product_error(headers): ) +@pytest.mark.anyio @pytest.mark.parametrize("status", [401, 403, 413, 500]) async def test_unsupported_product_error_not_raised_on_non_2xx(status): client = AsyncElasticsearch( @@ -709,6 +712,7 @@ async def test_unsupported_product_error_not_raised_on_non_2xx(status): assert e.meta.status == status +@pytest.mark.anyio @pytest.mark.parametrize("status", [404, 500]) async def test_api_error_raised_before_product_error(status): client = AsyncElasticsearch( @@ -737,6 +741,7 @@ async def test_api_error_raised_before_product_error(status): assert calls[0][0] == ("GET", "/") +@pytest.mark.anyio @pytest.mark.parametrize( "headers", [ diff --git a/test_elasticsearch/test_dsl/_async/test_document.py b/test_elasticsearch/test_dsl/_async/test_document.py index 5fe2d326c..8ac0fc887 100644 --- a/test_elasticsearch/test_dsl/_async/test_document.py +++ b/test_elasticsearch/test_dsl/_async/test_document.py @@ -582,21 +582,21 @@ def test_meta_fields_can_be_set_directly_in_init() -> None: assert md.meta.id is p -@pytest.mark.asyncio +@pytest.mark.anyio async def test_save_no_index(async_mock_client: Any) -> None: md = MyDoc() with raises(ValidationException): await md.save(using="mock") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_delete_no_index(async_mock_client: Any) -> None: md = MyDoc() with raises(ValidationException): await md.delete(using="mock") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_no_fields() -> None: md = MyDoc() with raises(IllegalOperation): diff --git a/test_elasticsearch/test_dsl/_async/test_index.py b/test_elasticsearch/test_dsl/_async/test_index.py index 624bab79a..e6668e264 100644 --- a/test_elasticsearch/test_dsl/_async/test_index.py +++ b/test_elasticsearch/test_dsl/_async/test_index.py @@ -190,7 +190,7 @@ def test_index_template_can_have_order() -> None: assert {"index_patterns": ["i-*"], "order": 2} == it.to_dict() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_index_template_save_result(async_mock_client: Any) -> None: it = AsyncIndexTemplate("test-template", "test-*") diff --git a/test_elasticsearch/test_dsl/_async/test_search.py b/test_elasticsearch/test_dsl/_async/test_search.py index a00ddf448..645a8d4a6 100644 --- a/test_elasticsearch/test_dsl/_async/test_search.py +++ b/test_elasticsearch/test_dsl/_async/test_search.py @@ -39,7 +39,7 @@ def test_expand__to_dot_is_respected() -> None: assert {"query": {"match": {"a__b": 42}}} == s.to_dict() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_execute_uses_cache() -> None: s = AsyncSearch() r = object() @@ -48,7 +48,7 @@ async def test_execute_uses_cache() -> None: assert r is await s.execute() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_cache_can_be_ignored(async_mock_client: Any) -> None: s = AsyncSearch(using="mock") r = object() @@ -58,7 +58,7 @@ async def test_cache_can_be_ignored(async_mock_client: Any) -> None: async_mock_client.search.assert_awaited_once_with(index=None, body={}) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_iter_iterates_over_hits() -> None: s = AsyncSearch() s._response = [1, 2, 3] # type: ignore[assignment] @@ -612,7 +612,7 @@ def test_from_dict_doesnt_need_query() -> None: assert {"size": 5} == s.to_dict() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_params_being_passed_to_search(async_mock_client: Any) -> None: s = AsyncSearch(using="mock") s = s.params(routing="42") @@ -704,7 +704,7 @@ def test_exclude() -> None: } == s.to_dict() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_delete_by_query(async_mock_client: Any) -> None: s = AsyncSearch(using="mock", index="i").query("match", lang="java") await s.delete() @@ -789,7 +789,7 @@ def test_rescore_query_to_dict() -> None: } -@pytest.mark.asyncio +@pytest.mark.anyio async def test_empty_search() -> None: s = AsyncEmptySearch(index="index-name") s = s.query("match", lang="java") diff --git a/test_elasticsearch/test_dsl/_async/test_update_by_query.py b/test_elasticsearch/test_dsl/_async/test_update_by_query.py index 9253623dc..7e2287db3 100644 --- a/test_elasticsearch/test_dsl/_async/test_update_by_query.py +++ b/test_elasticsearch/test_dsl/_async/test_update_by_query.py @@ -144,7 +144,7 @@ def test_from_dict_doesnt_need_query() -> None: assert {"script": {"source": "test"}} == ubq.to_dict() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_params_being_passed_to_search(async_mock_client: Any) -> None: ubq = AsyncUpdateByQuery(using="mock", index="i") ubq = ubq.params(routing="42") diff --git a/test_elasticsearch/test_dsl/async_sleep.py b/test_elasticsearch/test_dsl/async_sleep.py index ce5ced1c5..84ace53f0 100644 --- a/test_elasticsearch/test_dsl/async_sleep.py +++ b/test_elasticsearch/test_dsl/async_sleep.py @@ -15,10 +15,11 @@ # specific language governing permissions and limitations # under the License. -import asyncio from typing import Union +import anyio + async def sleep(secs: Union[int, float]) -> None: """Tests can use this function to sleep.""" - await asyncio.sleep(secs) + await anyio.sleep(secs) diff --git a/test_elasticsearch/test_dsl/conftest.py b/test_elasticsearch/test_dsl/conftest.py index 5dd83e54c..5951108f4 100644 --- a/test_elasticsearch/test_dsl/conftest.py +++ b/test_elasticsearch/test_dsl/conftest.py @@ -16,7 +16,6 @@ # under the License. -import asyncio import os import re import time @@ -25,9 +24,10 @@ from unittest import SkipTest from unittest.mock import AsyncMock, Mock -import pytest_asyncio +import anyio +import pytest +import sniffio from elastic_transport import ObjectApiResponse -from pytest import fixture, skip from elasticsearch import AsyncElasticsearch, Elasticsearch from elasticsearch.dsl import Search @@ -86,6 +86,10 @@ async def get_async_test_client( if elasticsearch_url.startswith("https://"): kw["ca_certs"] = CA_CERTS + # httpx is the only HTTP client that supports trio + if sniffio.current_async_library() == "trio": + kw["node_class"] = "httpxasync" + kw.update(kwargs) client = AsyncElasticsearch(elasticsearch_url, **kw) @@ -97,7 +101,7 @@ async def get_async_test_client( except ConnectionError: if wait and tries_left == 1: raise - await asyncio.sleep(0.1) + await anyio.sleep(0.1) await client.close() raise SkipTest("Elasticsearch failed to start.") @@ -110,7 +114,7 @@ def _get_version(version_string: str) -> Tuple[int, ...]: return tuple(int(v) if v.isdigit() else 999 for v in version) -@fixture +@pytest.fixture def client(elasticsearch_url) -> Elasticsearch: try: connection = get_test_client( @@ -121,10 +125,10 @@ def client(elasticsearch_url) -> Elasticsearch: wipe_cluster(connection) connection.close() except SkipTest: - skip() + pytest.skip() -@pytest_asyncio.fixture +@pytest.fixture async def async_client(elasticsearch_url) -> AsyncGenerator[AsyncElasticsearch, None]: try: connection = await get_async_test_client( @@ -135,10 +139,10 @@ async def async_client(elasticsearch_url) -> AsyncGenerator[AsyncElasticsearch, wipe_cluster(connection) await connection.close() except SkipTest: - skip() + pytest.skip() -@fixture +@pytest.fixture def es_version(client: Elasticsearch) -> Generator[Tuple[int, ...], None, None]: info = client.info() yield tuple( @@ -147,7 +151,7 @@ def es_version(client: Elasticsearch) -> Generator[Tuple[int, ...], None, None]: ) -@fixture +@pytest.fixture def write_client(client: Elasticsearch) -> Generator[Elasticsearch, None, None]: yield client for index_name in client.indices.get(index="test-*", expand_wildcards="all"): @@ -158,14 +162,14 @@ def write_client(client: Elasticsearch) -> Generator[Elasticsearch, None, None]: ) -@pytest_asyncio.fixture +@pytest.fixture async def async_write_client( write_client: Elasticsearch, async_client: AsyncElasticsearch ) -> AsyncGenerator[AsyncElasticsearch, None]: yield async_client -@fixture +@pytest.fixture def mock_client( dummy_response: ObjectApiResponse[Any], ) -> Generator[Elasticsearch, None, None]: @@ -179,7 +183,7 @@ def mock_client( connections._kwargs = {} -@fixture +@pytest.fixture def async_mock_client( dummy_response: ObjectApiResponse[Any], ) -> Generator[Elasticsearch, None, None]: @@ -195,7 +199,7 @@ def async_mock_client( async_connections._kwargs = {} -@fixture +@pytest.fixture def data_client(client: Elasticsearch) -> Generator[Elasticsearch, None, None]: # create mappings create_git_index(client, "git") @@ -208,14 +212,14 @@ def data_client(client: Elasticsearch) -> Generator[Elasticsearch, None, None]: client.options(ignore_status=404).indices.delete(index="flat-git") -@pytest_asyncio.fixture +@pytest.fixture async def async_data_client( data_client: Elasticsearch, async_client: AsyncElasticsearch ) -> AsyncGenerator[AsyncElasticsearch, None]: yield async_client -@fixture +@pytest.fixture def dummy_response() -> ObjectApiResponse[Any]: return ObjectApiResponse( meta=None, @@ -271,7 +275,7 @@ def dummy_response() -> ObjectApiResponse[Any]: ) -@fixture +@pytest.fixture def aggs_search() -> Search: s = Search(index="flat-git") s.aggs.bucket("popular_files", "terms", field="files", size=2).metric( @@ -284,7 +288,7 @@ def aggs_search() -> Search: return s -@fixture +@pytest.fixture def aggs_data() -> Dict[str, Any]: return { "took": 4, @@ -440,7 +444,7 @@ def make_pr(pr_module: Any) -> Any: ) -@fixture +@pytest.fixture def pull_request(write_client: Elasticsearch) -> sync_document.PullRequest: sync_document.PullRequest.init() pr = cast(sync_document.PullRequest, make_pr(sync_document)) @@ -448,7 +452,7 @@ def pull_request(write_client: Elasticsearch) -> sync_document.PullRequest: return pr -@pytest_asyncio.fixture +@pytest.fixture async def async_pull_request( async_write_client: AsyncElasticsearch, ) -> async_document.PullRequest: @@ -458,7 +462,7 @@ async def async_pull_request( return pr -@fixture +@pytest.fixture def setup_ubq_tests(client: Elasticsearch) -> str: index = "test-git" create_git_index(client, index) diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_analysis.py b/test_elasticsearch/test_dsl/test_integration/_async/test_analysis.py index 00598d4d5..c661359c0 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_analysis.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_analysis.py @@ -21,7 +21,7 @@ from elasticsearch.dsl import analyzer, token_filter, tokenizer -@pytest.mark.asyncio +@pytest.mark.anyio async def test_simulate_with_just__builtin_tokenizer( async_client: AsyncElasticsearch, ) -> None: @@ -32,7 +32,7 @@ async def test_simulate_with_just__builtin_tokenizer( assert tokens[0].token == "Hello World!" -@pytest.mark.asyncio +@pytest.mark.anyio async def test_simulate_complex(async_client: AsyncElasticsearch) -> None: a = analyzer( "my-analyzer", @@ -46,7 +46,7 @@ async def test_simulate_complex(async_client: AsyncElasticsearch) -> None: assert ["this", "works"] == [t.token for t in tokens] -@pytest.mark.asyncio +@pytest.mark.anyio async def test_simulate_builtin(async_client: AsyncElasticsearch) -> None: a = analyzer("my-analyzer", "english") tokens = (await a.async_simulate("fixes running")).tokens diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_document.py b/test_elasticsearch/test_dsl/test_integration/_async/test_document.py index 3d769c606..ba777145e 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_document.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_document.py @@ -141,7 +141,7 @@ class Index: name = "tags" -@pytest.mark.asyncio +@pytest.mark.anyio async def test_serialization(async_write_client: AsyncElasticsearch) -> None: await SerializationDoc.init() await async_write_client.index( @@ -173,7 +173,7 @@ async def test_serialization(async_write_client: AsyncElasticsearch) -> None: } -@pytest.mark.asyncio +@pytest.mark.anyio async def test_nested_inner_hits_are_wrapped_properly(async_pull_request: Any) -> None: history_query = Q( "nested", @@ -202,7 +202,7 @@ async def test_nested_inner_hits_are_wrapped_properly(async_pull_request: Any) - assert "score" in history.meta -@pytest.mark.asyncio +@pytest.mark.anyio async def test_nested_inner_hits_are_deserialized_properly( async_pull_request: Any, ) -> None: @@ -220,7 +220,7 @@ async def test_nested_inner_hits_are_deserialized_properly( assert isinstance(pr.comments[0].created_at, datetime) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_nested_top_hits_are_wrapped_properly(async_pull_request: Any) -> None: s = PullRequest.search() s.aggs.bucket("comments", "nested", path="comments").metric( @@ -233,7 +233,7 @@ async def test_nested_top_hits_are_wrapped_properly(async_pull_request: Any) -> assert isinstance(r.aggregations.comments.hits.hits[0], Comment) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_object_field(async_write_client: AsyncElasticsearch) -> None: await Wiki.init() w = Wiki( @@ -254,7 +254,7 @@ async def test_update_object_field(async_write_client: AsyncElasticsearch) -> No assert w.ranked == {"test1": 0.1, "topic2": 0.2} -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_script(async_write_client: AsyncElasticsearch) -> None: await Wiki.init() w = Wiki(owner=User(name="Honza Kral"), _id="elasticsearch-py", views=42) @@ -265,7 +265,7 @@ async def test_update_script(async_write_client: AsyncElasticsearch) -> None: assert w.views == 47 -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_script_with_dict(async_write_client: AsyncElasticsearch) -> None: await Wiki.init() w = Wiki(owner=User(name="Honza Kral"), _id="elasticsearch-py", views=42) @@ -283,7 +283,7 @@ async def test_update_script_with_dict(async_write_client: AsyncElasticsearch) - assert w.views == 47 -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_retry_on_conflict(async_write_client: AsyncElasticsearch) -> None: await Wiki.init() w = Wiki(owner=User(name="Honza Kral"), _id="elasticsearch-py", views=42) @@ -305,7 +305,7 @@ async def test_update_retry_on_conflict(async_write_client: AsyncElasticsearch) assert w.views == 52 -@pytest.mark.asyncio +@pytest.mark.anyio @pytest.mark.parametrize("retry_on_conflict", [None, 0]) async def test_update_conflicting_version( async_write_client: AsyncElasticsearch, retry_on_conflict: bool @@ -329,7 +329,7 @@ async def test_update_conflicting_version( ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_save_and_update_return_doc_meta( async_write_client: AsyncElasticsearch, ) -> None: @@ -364,14 +364,14 @@ async def test_save_and_update_return_doc_meta( } -@pytest.mark.asyncio +@pytest.mark.anyio async def test_init(async_write_client: AsyncElasticsearch) -> None: await Repository.init(index="test-git") assert await async_write_client.indices.exists(index="test-git") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_get_raises_404_on_index_missing( async_data_client: AsyncElasticsearch, ) -> None: @@ -379,7 +379,7 @@ async def test_get_raises_404_on_index_missing( await Repository.get("elasticsearch-dsl-php", index="not-there") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_get_raises_404_on_non_existent_id( async_data_client: AsyncElasticsearch, ) -> None: @@ -387,7 +387,7 @@ async def test_get_raises_404_on_non_existent_id( await Repository.get("elasticsearch-dsl-php") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_get_returns_none_if_404_ignored( async_data_client: AsyncElasticsearch, ) -> None: @@ -396,7 +396,7 @@ async def test_get_returns_none_if_404_ignored( ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_get_returns_none_if_404_ignored_and_index_doesnt_exist( async_data_client: AsyncElasticsearch, ) -> None: @@ -405,7 +405,7 @@ async def test_get_returns_none_if_404_ignored_and_index_doesnt_exist( ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_get(async_data_client: AsyncElasticsearch) -> None: elasticsearch_repo = await Repository.get("elasticsearch-dsl-py") @@ -414,17 +414,17 @@ async def test_get(async_data_client: AsyncElasticsearch) -> None: assert datetime(2014, 3, 3) == elasticsearch_repo.created_at -@pytest.mark.asyncio +@pytest.mark.anyio async def test_exists_return_true(async_data_client: AsyncElasticsearch) -> None: assert await Repository.exists("elasticsearch-dsl-py") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_exists_false(async_data_client: AsyncElasticsearch) -> None: assert not await Repository.exists("elasticsearch-dsl-php") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_get_with_tz_date(async_data_client: AsyncElasticsearch) -> None: first_commit = await Commit.get( id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="elasticsearch-dsl-py" @@ -438,7 +438,7 @@ async def test_get_with_tz_date(async_data_client: AsyncElasticsearch) -> None: ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_save_with_tz_date(async_data_client: AsyncElasticsearch) -> None: tzinfo = timezone("Europe/Prague") first_commit = await Commit.get( @@ -470,7 +470,7 @@ async def test_save_with_tz_date(async_data_client: AsyncElasticsearch) -> None: ] -@pytest.mark.asyncio +@pytest.mark.anyio async def test_mget(async_data_client: AsyncElasticsearch) -> None: commits = await Commit.mget(COMMIT_DOCS_WITH_MISSING) assert commits[0] is None @@ -481,7 +481,7 @@ async def test_mget(async_data_client: AsyncElasticsearch) -> None: assert commits[3].meta.id == "eb3e543323f189fd7b698e66295427204fff5755" -@pytest.mark.asyncio +@pytest.mark.anyio async def test_mget_raises_exception_when_missing_param_is_invalid( async_data_client: AsyncElasticsearch, ) -> None: @@ -489,7 +489,7 @@ async def test_mget_raises_exception_when_missing_param_is_invalid( await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raj") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_mget_raises_404_when_missing_param_is_raise( async_data_client: AsyncElasticsearch, ) -> None: @@ -497,7 +497,7 @@ async def test_mget_raises_404_when_missing_param_is_raise( await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raise") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_mget_ignores_missing_docs_when_missing_param_is_skip( async_data_client: AsyncElasticsearch, ) -> None: @@ -508,7 +508,7 @@ async def test_mget_ignores_missing_docs_when_missing_param_is_skip( assert commits[1].meta.id == "eb3e543323f189fd7b698e66295427204fff5755" -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_works_from_search_response( async_data_client: AsyncElasticsearch, ) -> None: @@ -523,7 +523,7 @@ async def test_update_works_from_search_response( assert "elasticsearch" == new_version.owner.name -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update(async_data_client: AsyncElasticsearch) -> None: elasticsearch_repo = await Repository.get("elasticsearch-dsl-py") assert elasticsearch_repo is not None @@ -550,7 +550,7 @@ async def test_update(async_data_client: AsyncElasticsearch) -> None: assert "primary_term" in new_version.meta -@pytest.mark.asyncio +@pytest.mark.anyio async def test_save_updates_existing_doc(async_data_client: AsyncElasticsearch) -> None: elasticsearch_repo = await Repository.get("elasticsearch-dsl-py") assert elasticsearch_repo is not None @@ -565,7 +565,7 @@ async def test_save_updates_existing_doc(async_data_client: AsyncElasticsearch) assert new_repo["_seq_no"] == elasticsearch_repo.meta.seq_no -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_empty_field(async_client: AsyncElasticsearch) -> None: await Tags._index.delete(ignore_unavailable=True) await Tags.init() @@ -578,7 +578,7 @@ async def test_update_empty_field(async_client: AsyncElasticsearch) -> None: assert r.hits[0].tags == [] -@pytest.mark.asyncio +@pytest.mark.anyio async def test_save_automatically_uses_seq_no_and_primary_term( async_data_client: AsyncElasticsearch, ) -> None: @@ -590,7 +590,7 @@ async def test_save_automatically_uses_seq_no_and_primary_term( await elasticsearch_repo.save() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_delete_automatically_uses_seq_no_and_primary_term( async_data_client: AsyncElasticsearch, ) -> None: @@ -608,7 +608,7 @@ def assert_doc_equals(expected: Any, actual: Any) -> None: assert actual[f] == expected[f] -@pytest.mark.asyncio +@pytest.mark.anyio async def test_can_save_to_different_index( async_write_client: AsyncElasticsearch, ) -> None: @@ -626,7 +626,7 @@ async def test_can_save_to_different_index( ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_save_without_skip_empty_will_include_empty_fields( async_write_client: AsyncElasticsearch, ) -> None: @@ -651,7 +651,7 @@ async def test_save_without_skip_empty_will_include_empty_fields( ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_delete(async_write_client: AsyncElasticsearch) -> None: await async_write_client.create( index="test-document", @@ -673,12 +673,12 @@ async def test_delete(async_write_client: AsyncElasticsearch) -> None: ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_search(async_data_client: AsyncElasticsearch) -> None: assert await Repository.search().count() == 1 -@pytest.mark.asyncio +@pytest.mark.anyio async def test_search_returns_proper_doc_classes( async_data_client: AsyncElasticsearch, ) -> None: @@ -690,7 +690,7 @@ async def test_search_returns_proper_doc_classes( assert elasticsearch_repo.owner.name == "elasticsearch" -@pytest.mark.asyncio +@pytest.mark.anyio async def test_refresh_mapping(async_data_client: AsyncElasticsearch) -> None: class Commit(AsyncDocument): class Index: @@ -705,7 +705,7 @@ class Index: assert isinstance(Commit._index._mapping["committed_date"], Date) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_highlight_in_meta(async_data_client: AsyncElasticsearch) -> None: commit = ( await Commit.search() @@ -720,7 +720,7 @@ async def test_highlight_in_meta(async_data_client: AsyncElasticsearch) -> None: assert len(commit.meta.highlight["description"]) > 0 -@pytest.mark.asyncio +@pytest.mark.anyio async def test_bulk(async_data_client: AsyncElasticsearch) -> None: class Address(InnerDoc): street: str @@ -808,7 +808,7 @@ async def gen3() -> AsyncIterator[Union[Doc, Dict[str, Any]]]: } -@pytest.mark.asyncio +@pytest.mark.anyio async def test_legacy_dense_vector( async_client: AsyncElasticsearch, es_version: Tuple[int, ...] ) -> None: @@ -832,7 +832,7 @@ class Index: assert docs[0].float_vector == doc.float_vector -@pytest.mark.asyncio +@pytest.mark.anyio async def test_dense_vector( async_client: AsyncElasticsearch, es_version: Tuple[int, ...] ) -> None: @@ -862,7 +862,7 @@ class Index: assert docs[0].bit_vector == doc.bit_vector -@pytest.mark.asyncio +@pytest.mark.anyio async def test_copy_to(async_client: AsyncElasticsearch) -> None: class Person(AsyncDocument): first_name: M[str] = mapped_field(Text(copy_to=["full_name", "all"])) diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py b/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py index ae99873f8..1229ece20 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py @@ -138,7 +138,7 @@ async def load_db(): await Employee._index.refresh() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_esql(async_client): await load_db() @@ -184,7 +184,7 @@ async def test_esql(async_client): assert r.body["values"] == [["Luna"], ["Cannon"]] -@pytest.mark.asyncio +@pytest.mark.anyio async def test_esql_dsl(async_client): await load_db() diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_faceted_search.py b/test_elasticsearch/test_dsl/test_integration/_async/test_faceted_search.py index bb0fd9257..82f1a8767 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_faceted_search.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_faceted_search.py @@ -126,7 +126,7 @@ class PRSearch(AsyncFacetedSearch): return PRSearch -@pytest.mark.asyncio +@pytest.mark.anyio async def test_facet_with_custom_metric(async_data_client: AsyncElasticsearch) -> None: ms = MetricSearch() r = await ms.execute() @@ -136,7 +136,7 @@ async def test_facet_with_custom_metric(async_data_client: AsyncElasticsearch) - assert dates[0] == 1399038439000 -@pytest.mark.asyncio +@pytest.mark.anyio async def test_nested_facet( async_pull_request: PullRequest, pr_search_cls: Type[AsyncFacetedSearch] ) -> None: @@ -147,7 +147,7 @@ async def test_nested_facet( assert [(datetime(2018, 1, 1, 0, 0), 1, False)] == r.facets.comments -@pytest.mark.asyncio +@pytest.mark.anyio async def test_nested_facet_with_filter( async_pull_request: PullRequest, pr_search_cls: Type[AsyncFacetedSearch] ) -> None: @@ -162,7 +162,7 @@ async def test_nested_facet_with_filter( assert not r.hits -@pytest.mark.asyncio +@pytest.mark.anyio async def test_datehistogram_facet( async_data_client: AsyncElasticsearch, repo_search_cls: Type[AsyncFacetedSearch] ) -> None: @@ -173,7 +173,7 @@ async def test_datehistogram_facet( assert [(datetime(2014, 3, 1, 0, 0), 1, False)] == r.facets.created -@pytest.mark.asyncio +@pytest.mark.anyio async def test_boolean_facet( async_data_client: AsyncElasticsearch, repo_search_cls: Type[AsyncFacetedSearch] ) -> None: @@ -186,7 +186,7 @@ async def test_boolean_facet( assert value is True -@pytest.mark.asyncio +@pytest.mark.anyio async def test_empty_search_finds_everything( async_data_client: AsyncElasticsearch, es_version: Tuple[int, ...], @@ -236,7 +236,7 @@ async def test_empty_search_finds_everything( ] == r.facets.deletions -@pytest.mark.asyncio +@pytest.mark.anyio async def test_term_filters_are_shown_as_selected_and_data_is_filtered( async_data_client: AsyncElasticsearch, commit_search_cls: Type[AsyncFacetedSearch] ) -> None: @@ -283,7 +283,7 @@ async def test_term_filters_are_shown_as_selected_and_data_is_filtered( ] == r.facets.deletions -@pytest.mark.asyncio +@pytest.mark.anyio async def test_range_filters_are_shown_as_selected_and_data_is_filtered( async_data_client: AsyncElasticsearch, commit_search_cls: Type[AsyncFacetedSearch] ) -> None: @@ -294,7 +294,7 @@ async def test_range_filters_are_shown_as_selected_and_data_is_filtered( assert 19 == r.hits.total.value # type: ignore[attr-defined] -@pytest.mark.asyncio +@pytest.mark.anyio async def test_pagination( async_data_client: AsyncElasticsearch, commit_search_cls: Type[AsyncFacetedSearch] ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_index.py b/test_elasticsearch/test_dsl/test_integration/_async/test_index.py index e150d1e59..3e95e89e3 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_index.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_index.py @@ -34,7 +34,7 @@ class Post(AsyncDocument): published_from = Date() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_index_template_works(async_write_client: AsyncElasticsearch) -> None: it = AsyncIndexTemplate("test-template", "test-legacy-*") it.document(Post) @@ -56,7 +56,7 @@ async def test_index_template_works(async_write_client: AsyncElasticsearch) -> N } == await async_write_client.indices.get_mapping(index="test-legacy-blog") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_composable_index_template_works( async_write_client: AsyncElasticsearch, ) -> None: @@ -80,7 +80,7 @@ async def test_composable_index_template_works( } == await async_write_client.indices.get_mapping(index="test-blog") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_index_can_be_saved_even_with_settings( async_write_client: AsyncElasticsearch, ) -> None: @@ -98,13 +98,13 @@ async def test_index_can_be_saved_even_with_settings( ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_index_exists(async_data_client: AsyncElasticsearch) -> None: assert await AsyncIndex("git").exists() assert not await AsyncIndex("not-there").exists() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_index_can_be_created_with_settings_and_mappings( async_write_client: AsyncElasticsearch, ) -> None: @@ -132,7 +132,7 @@ async def test_index_can_be_created_with_settings_and_mappings( } -@pytest.mark.asyncio +@pytest.mark.anyio async def test_delete(async_write_client: AsyncElasticsearch) -> None: await async_write_client.indices.create( index="test-index", @@ -144,7 +144,7 @@ async def test_delete(async_write_client: AsyncElasticsearch) -> None: assert not await async_write_client.indices.exists(index="test-index") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_multiple_indices_with_same_doc_type_work( async_write_client: AsyncElasticsearch, ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_mapping.py b/test_elasticsearch/test_dsl/test_integration/_async/test_mapping.py index f370c89c4..c7aa02a67 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_mapping.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_mapping.py @@ -22,7 +22,7 @@ from elasticsearch.dsl import AsyncMapping, analysis, exceptions -@pytest.mark.asyncio +@pytest.mark.anyio async def test_mapping_saved_into_es(async_write_client: AsyncElasticsearch) -> None: m = AsyncMapping() m.field( @@ -43,7 +43,7 @@ async def test_mapping_saved_into_es(async_write_client: AsyncElasticsearch) -> } == await async_write_client.indices.get_mapping(index="test-mapping") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_mapping_saved_into_es_when_index_already_exists_closed( async_write_client: AsyncElasticsearch, ) -> None: @@ -71,7 +71,7 @@ async def test_mapping_saved_into_es_when_index_already_exists_closed( } == await async_write_client.indices.get_mapping(index="test-mapping") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_mapping_saved_into_es_when_index_already_exists_with_analysis( async_write_client: AsyncElasticsearch, ) -> None: @@ -103,7 +103,7 @@ async def test_mapping_saved_into_es_when_index_already_exists_with_analysis( } == await async_write_client.indices.get_mapping(index="test-mapping") -@pytest.mark.asyncio +@pytest.mark.anyio async def test_mapping_gets_updated_from_es( async_write_client: AsyncElasticsearch, ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_search.py b/test_elasticsearch/test_dsl/test_integration/_async/test_search.py index a63f6746a..2499b8d03 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_search.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_search.py @@ -52,7 +52,7 @@ class Index: name = "flat-git" -@pytest.mark.asyncio +@pytest.mark.anyio async def test_filters_aggregation_buckets_are_accessible( async_data_client: AsyncElasticsearch, ) -> None: @@ -77,7 +77,7 @@ async def test_filters_aggregation_buckets_are_accessible( ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_top_hits_are_wrapped_in_response( async_data_client: AsyncElasticsearch, ) -> None: @@ -96,7 +96,7 @@ async def test_top_hits_are_wrapped_in_response( assert isinstance(hits[0], Commit) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_inner_hits_are_wrapped_in_response( async_data_client: AsyncElasticsearch, ) -> None: @@ -112,7 +112,7 @@ async def test_inner_hits_are_wrapped_in_response( ) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_inner_hits_are_serialized_to_dict( async_data_client: AsyncElasticsearch, ) -> None: @@ -133,7 +133,7 @@ async def test_inner_hits_are_serialized_to_dict( assert isinstance(d["hits"]["hits"][0]["inner_hits"]["repo"], dict) -@pytest.mark.asyncio +@pytest.mark.anyio async def test_scan_respects_doc_types(async_data_client: AsyncElasticsearch) -> None: repos = [repo async for repo in Repository.search().scan()] @@ -142,7 +142,7 @@ async def test_scan_respects_doc_types(async_data_client: AsyncElasticsearch) -> assert repos[0].organization == "elasticsearch" -@pytest.mark.asyncio +@pytest.mark.anyio async def test_scan_iterates_through_all_docs( async_data_client: AsyncElasticsearch, ) -> None: @@ -154,7 +154,7 @@ async def test_scan_iterates_through_all_docs( assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits} -@pytest.mark.asyncio +@pytest.mark.anyio async def test_search_after(async_data_client: AsyncElasticsearch) -> None: page_size = 7 s = AsyncSearch(index="flat-git")[:page_size].sort("authored_date") @@ -170,7 +170,7 @@ async def test_search_after(async_data_client: AsyncElasticsearch) -> None: assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits} -@pytest.mark.asyncio +@pytest.mark.anyio async def test_search_after_no_search(async_data_client: AsyncElasticsearch) -> None: s = AsyncSearch(index="flat-git") with raises( @@ -184,7 +184,7 @@ async def test_search_after_no_search(async_data_client: AsyncElasticsearch) -> s.search_after() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_search_after_no_sort(async_data_client: AsyncElasticsearch) -> None: s = AsyncSearch(index="flat-git") r = await s.execute() @@ -194,7 +194,7 @@ async def test_search_after_no_sort(async_data_client: AsyncElasticsearch) -> No r.search_after() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_search_after_no_results(async_data_client: AsyncElasticsearch) -> None: s = AsyncSearch(index="flat-git")[:100].sort("authored_date") r = await s.execute() @@ -208,7 +208,7 @@ async def test_search_after_no_results(async_data_client: AsyncElasticsearch) -> r.search_after() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_point_in_time(async_data_client: AsyncElasticsearch) -> None: page_size = 7 commits = [] @@ -229,7 +229,7 @@ async def test_point_in_time(async_data_client: AsyncElasticsearch) -> None: assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits} -@pytest.mark.asyncio +@pytest.mark.anyio async def test_iterate(async_data_client: AsyncElasticsearch) -> None: s = AsyncSearch(index="flat-git") @@ -239,7 +239,7 @@ async def test_iterate(async_data_client: AsyncElasticsearch) -> None: assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits} -@pytest.mark.asyncio +@pytest.mark.anyio async def test_response_is_cached(async_data_client: AsyncElasticsearch) -> None: s = Repository.search() repos = [repo async for repo in s] @@ -248,7 +248,7 @@ async def test_response_is_cached(async_data_client: AsyncElasticsearch) -> None assert s._response.hits == repos -@pytest.mark.asyncio +@pytest.mark.anyio async def test_multi_search(async_data_client: AsyncElasticsearch) -> None: s1 = Repository.search() s2 = AsyncSearch[Repository](index="flat-git") @@ -266,7 +266,7 @@ async def test_multi_search(async_data_client: AsyncElasticsearch) -> None: assert r2._search is s2 -@pytest.mark.asyncio +@pytest.mark.anyio async def test_multi_missing(async_data_client: AsyncElasticsearch) -> None: s1 = Repository.search() s2 = AsyncSearch[Repository](index="flat-git") @@ -290,7 +290,7 @@ async def test_multi_missing(async_data_client: AsyncElasticsearch) -> None: assert r3 is None -@pytest.mark.asyncio +@pytest.mark.anyio async def test_raw_subfield_can_be_used_in_aggs( async_data_client: AsyncElasticsearch, ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_update_by_query.py b/test_elasticsearch/test_dsl/test_integration/_async/test_update_by_query.py index b051d284a..880bb9482 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_update_by_query.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_update_by_query.py @@ -22,7 +22,7 @@ from elasticsearch.dsl.search import Q -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_by_query_no_script( async_write_client: AsyncElasticsearch, setup_ubq_tests: str ) -> None: @@ -44,7 +44,7 @@ async def test_update_by_query_no_script( assert response.success() -@pytest.mark.asyncio +@pytest.mark.anyio async def test_update_by_query_with_script( async_write_client: AsyncElasticsearch, setup_ubq_tests: str ) -> None: @@ -64,7 +64,7 @@ async def test_update_by_query_with_script( assert response.version_conflicts == 0 -@pytest.mark.asyncio +@pytest.mark.anyio async def test_delete_by_query_with_script( async_write_client: AsyncElasticsearch, setup_ubq_tests: str ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_alias_migration.py b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_alias_migration.py index d2b4294a4..ea2db3362 100644 --- a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_alias_migration.py +++ b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_alias_migration.py @@ -23,7 +23,7 @@ from ..async_examples.alias_migration import ALIAS, PATTERN, BlogPost, migrate -@pytest.mark.asyncio +@pytest.mark.anyio async def test_alias_migration(async_write_client: AsyncElasticsearch) -> None: # create the index await alias_migration.setup() diff --git a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_completion.py b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_completion.py index 13e73e14a..cb923e474 100644 --- a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_completion.py +++ b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_completion.py @@ -22,7 +22,7 @@ from ..async_examples.completion import Person -@pytest.mark.asyncio +@pytest.mark.anyio async def test_person_suggests_on_all_variants_of_name( async_write_client: AsyncElasticsearch, ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_composite_aggs.py b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_composite_aggs.py index 2d3ab2df7..5110bbd50 100644 --- a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_composite_aggs.py +++ b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_composite_aggs.py @@ -23,7 +23,7 @@ from ..async_examples.composite_agg import scan_aggs -@pytest.mark.asyncio +@pytest.mark.anyio async def test_scan_aggs_exhausts_all_files( async_data_client: AsyncElasticsearch, ) -> None: @@ -34,7 +34,7 @@ async def test_scan_aggs_exhausts_all_files( assert len(file_list) == 26 -@pytest.mark.asyncio +@pytest.mark.anyio async def test_scan_aggs_with_multiple_aggs( async_data_client: AsyncElasticsearch, ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_parent_child.py b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_parent_child.py index a730c8839..877c26fd9 100644 --- a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_parent_child.py +++ b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_parent_child.py @@ -18,7 +18,6 @@ from datetime import datetime import pytest -import pytest_asyncio from elasticsearch import AsyncElasticsearch from elasticsearch.dsl import Q @@ -42,7 +41,7 @@ ) -@pytest_asyncio.fixture +@pytest.fixture async def question(async_write_client: AsyncElasticsearch) -> Question: await setup() assert await async_write_client.indices.exists_index_template(name="base") @@ -64,7 +63,7 @@ async def question(async_write_client: AsyncElasticsearch) -> Question: return q -@pytest.mark.asyncio +@pytest.mark.anyio async def test_comment( async_write_client: AsyncElasticsearch, question: Question ) -> None: @@ -79,7 +78,7 @@ async def test_comment( assert c.author.username == "fxdgear" -@pytest.mark.asyncio +@pytest.mark.anyio async def test_question_answer( async_write_client: AsyncElasticsearch, question: Question ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_percolate.py b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_percolate.py index cf1721b8e..3b61c96e5 100644 --- a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_percolate.py +++ b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_percolate.py @@ -22,7 +22,7 @@ from ..async_examples.percolate import BlogPost, setup -@pytest.mark.asyncio +@pytest.mark.anyio async def test_post_gets_tagged_automatically( async_write_client: AsyncElasticsearch, ) -> None: diff --git a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py index 3af9a877f..347339808 100644 --- a/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py +++ b/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py @@ -26,7 +26,7 @@ from elasticsearch import AsyncElasticsearch -@pytest.mark.asyncio +@pytest.mark.anyio async def test_vector_search( async_write_client: AsyncElasticsearch, es_version: Tuple[int, ...] ) -> None: diff --git a/test_elasticsearch/test_server/test_rest_api_spec.py b/test_elasticsearch/test_server/test_rest_api_spec.py index 768453c10..4e3ff74a9 100644 --- a/test_elasticsearch/test_server/test_rest_api_spec.py +++ b/test_elasticsearch/test_server/test_rest_api_spec.py @@ -20,6 +20,7 @@ some integration tests. These files are shared among all official Elasticsearch clients. """ +import copy import io import json import os @@ -117,6 +118,7 @@ def __init__(self, client): self._state = {} def use_spec(self, test_spec): + test_spec = copy.deepcopy(test_spec) self._setup_code = test_spec.pop("setup", None) self._run_code = test_spec.pop("run", None) self._teardown_code = test_spec.pop("teardown", None) diff --git a/utils/run-unasync-dsl.py b/utils/run-unasync-dsl.py index b74c748fa..d4830d5ff 100644 --- a/utils/run-unasync-dsl.py +++ b/utils/run-unasync-dsl.py @@ -74,7 +74,6 @@ def main(check=False): "async_examples": "examples", "async_sleep": "sleep", "assert_awaited_once_with": "assert_called_once_with", - "pytest_asyncio": "pytest", "asynccontextmanager": "contextmanager", } rules = [ @@ -129,7 +128,7 @@ def main(check=False): [ "sed", "-i.bak", - "s/pytest.mark.asyncio/pytest.mark.sync/", + "s/pytest.mark.anyio/pytest.mark.sync/", f"{output_dir}{file}", ] )