From 36393b7f1ccbda6546e66c690d5329ef06bf9aab Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Mon, 27 Jan 2025 15:59:35 +0000 Subject: [PATCH 1/3] add readthedocs content to the guide --- docs/guide/async.asciidoc | 127 +++++++++++++++++ docs/guide/examples.asciidoc | 176 ++++++++++++++++++++++++ docs/guide/getting-started.asciidoc | 58 +++++++- docs/guide/index-custom-title-page.html | 5 +- docs/guide/index.asciidoc | 2 + 5 files changed, 362 insertions(+), 6 deletions(-) create mode 100644 docs/guide/async.asciidoc diff --git a/docs/guide/async.asciidoc b/docs/guide/async.asciidoc new file mode 100644 index 000000000..ce30bcf41 --- /dev/null +++ b/docs/guide/async.asciidoc @@ -0,0 +1,127 @@ +[[async]] +== Using with asyncio + +The `elasticsearch` package supports async/await with +https://docs.python.org/3/library/asyncio.html[asyncio] and +https://docs.aiohttp.org[aiohttp]. You can either install `aiohttp` +directly or use the `[async]` extra: + +[source,bash] +---- +$ python -m pip install elasticsearch aiohttp + +# - OR - + +$ python -m pip install elasticsearch[async] +---- + +=== Getting Started with Async + +After installation all async API endpoints are available via +`~elasticsearch.AsyncElasticsearch` and are used in the same way as +other APIs, just with an extra `await`: + +[source,python] +---- +import asyncio +from elasticsearch import AsyncElasticsearch + +client = AsyncElasticsearch() + +async def main(): + resp = await client.search( + index="documents", + body={"query": {"match_all": {}}}, + size=20, + ) + print(resp) + +loop = asyncio.get_event_loop() +loop.run_until_complete(main()) +---- + +All APIs that are available under the sync client are also available +under the async client. + +=== ASGI Applications and Elastic APM + +https://asgi.readthedocs.io[ASGI] (Asynchronous Server Gateway +Interface) is a new way to serve Python web applications making use of +async I/O to achieve better performance. Some examples of ASGI +frameworks include FastAPI, Django 3.0+, and Starlette. If you're +using one of these frameworks along with Elasticsearch then you should +be using `~elasticsearch.AsyncElasticsearch` to avoid blocking the event +loop with synchronous network calls for optimal performance. + +https://www.elastic.co/guide/en/apm/agent/python/current/index.html[Elastic +APM] also supports tracing of async Elasticsearch queries just the same +as synchronous queries. For an example on how to configure +`AsyncElasticsearch` with a popular ASGI framework +https://fastapi.tiangolo.com/[FastAPI] and APM tracing there is a +https://github.com/elastic/elasticsearch-py/tree/master/examples/fastapi-apm[pre-built +example] in the `examples/fastapi-apm` directory. + +=== Frequently Asked Questions + +==== ValueError when initializing `AsyncElasticsearch`? + +If when trying to use `AsyncElasticsearch` you receive +`ValueError: You must have 'aiohttp' installed to use AiohttpHttpNode` +you should ensure that you have `aiohttp` installed in your environment +(check with `$ python -m pip freeze | grep aiohttp`). Otherwise, +async support won't be available. + +==== What about the `elasticsearch-async` package? + +Previously asyncio was supported separately via the +https://github.com/elastic/elasticsearch-py-async[elasticsearch-async] +package. The `elasticsearch-async` package has been deprecated in favor +of `AsyncElasticsearch` provided by the `elasticsearch` package in v7.8 +and onwards. + +==== Receiving 'Unclosed client session / connector' warning? + +This warning is created by `aiohttp` when an open HTTP connection is +garbage collected. You'll typically run into this when closing your +application. To resolve the issue ensure that +`~elasticsearch.AsyncElasticsearch.close` is called before the +`~elasticsearch.AsyncElasticsearch` instance is garbage collected. + +For example if using FastAPI that might look like this: + +[source,python] +---- +import os +from contextlib import asynccontextmanager + +from fastapi import FastAPI +from elasticsearch import AsyncElasticsearch + +ELASTICSEARCH_URL = os.environ["ELASTICSEARCH_URL"] +client = None + +@asynccontextmanager +async def lifespan(app: FastAPI): + global client + client = AsyncElasticsearch(ELASTICSEARCH_URL) + yield + await client.close() + +app = FastAPI(lifespan=lifespan) + +@app.get("/") +async def main(): + return await client.info() +---- + +You can run this example by saving it to `main.py` and executing +`ELASTICSEARCH_URL=http://localhost:9200 uvicorn main:app`. + +=== Async Helpers + +Async variants of all helpers are available in `elasticsearch.helpers` +and are all prefixed with `async_*`. You'll notice that these APIs +are identical to the ones in the sync <> documentation. + +All async helpers that accept an iterator or generator also accept async +iterators and async generators. diff --git a/docs/guide/examples.asciidoc b/docs/guide/examples.asciidoc index b9a5650a6..575f43bbe 100644 --- a/docs/guide/examples.asciidoc +++ b/docs/guide/examples.asciidoc @@ -109,3 +109,179 @@ method: ---------------------------- client.delete(index="test-index", id=1) ---------------------------- + +[discrete] +[[ex-interactive]] +=== Interactive examples + +The https://github.com/elastic/elasticsearch-labs[elasticsearch-labs] +repo contains interactive and executable +https://github.com/elastic/elasticsearch-labs/tree/main/notebooks[Python +notebooks], sample apps, and resources for testing out Elasticsearch, +using the Python client. These examples are mainly focused on vector +search, hybrid search and generative AI use cases, but you'll also find +examples of basic operations like creating index mappings and performing +lexical search. + +[discrete] +==== Search notebooks + +The +https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/search[Search] +folder is a good place to start if you're new to Elasticsearch. This +folder contains a number of notebooks that demonstrate the fundamentals +of Elasticsearch, like indexing vectors, running lexical, semantic and +_hybrid_ searches, and more. + +The following notebooks are available: + +[arabic, start=0] +* https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/00-quick-start.ipynb[Quick +start] +* https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/01-keyword-querying-filtering.ipynb[Keyword, +querying, filtering] +* https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/02-hybrid-search.ipynb[Hybrid +search] +* https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/03-ELSER.ipynb[Semantic +search with ELSER] +* https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/04-multilingual.ipynb[Multilingual +semantic search] +* https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/05-query-rules.ipynb[Query +rules] +* https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/06-synonyms-api.ipynb[Synonyms +API quick start] + +Here's a brief overview of what you'll learn in each notebook. + +[discrete] +===== Quick start + +In the +https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/00-quick-start.ipynb[00-quick-start.ipynb] +notebook you'll learn how to: + +* Use the Elasticsearch Python client for various operations. +* Create and define an index for a sample dataset with +`dense_vector` fields. +* Transform book titles into embeddings using +https://www.sbert.net[Sentence Transformers] and index them into +Elasticsearch. +* Perform k-nearest neighbors (knn) semantic searches. +* Integrate traditional text-based search with semantic search, for a +hybrid search system. +* Use reciprocal rank fusion (RRF) to intelligently combine search +results from different retrieval systems. + +[discrete] +===== Keyword, querying, filtering + +In the +https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/01-keyword-querying-filtering.ipynb[01-keyword-querying-filtering.ipynb] +notebook, you'll learn how to: + +* Use +https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html[query +and filter contexts] to search and filter documents in Elasticsearch. +* Execute full-text searches with `match` and `multi-match` queries. +* Query and filter documents based on `text`, `number`, `date`, or +`boolean` values. +* Run multi-field searches using the `multi-match` query. +* Prioritize specific fields in the `multi-match` query for tailored +results. + +[discrete] +===== Hybrid search + +In the +https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/02-hybrid-search.ipynb[02-hybrid-search.ipynb] +notebook, you'll learn how to: + +* Combine results of traditional text-based search with semantic search, +for a hybrid search system. +* Transform fields in the sample dataset into embeddings using the +Sentence Transformer model and index them into Elasticsearch. +* Use the +https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html#rrf-api[RRF +API] to combine the results of a `match` query and a `kNN` semantic +search. +* Walk through a super simple toy example that demonstrates, step by +step, how RRF ranking works. + +[discrete] +===== Semantic search with ELSER + +In the +https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/03-ELSER.ipynb[03-ELSER.ipynb] +notebook, you'll learn how to: + +* Use the Elastic Learned Sparse Encoder (ELSER) for text +expansion-powered semantic search, out of the box — without training, +fine-tuning, or embeddings generation. +* Download and deploy the ELSER model in your Elastic environment. +* Create an Elasticsearch index named [.title-ref]#search-movies# with +specific mappings and index a dataset of movie descriptions. +* Create an ingest pipeline containing an inference processor for ELSER +model execution. +* Reindex the data from [.title-ref]#search-movies# into another index, +[.title-ref]#elser-movies#, using the ELSER pipeline for text expansion. +* Observe the results of running the documents through the model by +inspecting the additional terms it adds to documents, which enhance +searchability. +* Perform simple keyword searches on the [.title-ref]#elser-movies# +index to assess the impact of ELSER's text expansion. +* Execute ELSER-powered semantic searches using the `text_expansion` +query. + +[discrete] +===== Multilingual semantic search + +In the +https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/04-multilingual.ipynb[04-multilingual.ipynb] +notebook, you'll learn how to: + +* Use a multilingual embedding model for semantic search across +languages. +* Transform fields in the sample dataset into embeddings using the +Sentence Transformer model and index them into Elasticsearch. +* Use filtering with a `kNN` semantic search. +* Walk through a super simple toy example that demonstrates, step by +step, how multilingual search works across languages, and within +non-English languages. + +[discrete] +===== Query rules + +In the +https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/05-query-rules.ipynb[05-query-rules.ipynb] +notebook, you'll learn how to: + +* Use the query rules management APIs to create and edit promotional +rules based on contextual queries. +* Apply these query rules by using the `rule_query` in Query DSL. + +[discrete] +===== Synonyms API quick start + +In the +https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/06-synonyms-api.ipynb[06-synonyms-api.ipynb] +notebook, you'll learn how to: + +* Use the synonyms management API to create a synonyms set to enhance +your search recall. +* Configure an index to use search-time synonyms. +* Update synonyms in real time. +* Run queries that are enhanced by synonyms. + +[discrete] +==== Other notebooks + +* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/generative-ai[Generative +AI]. Notebooks that demonstrate various use cases for Elasticsearch as +the retrieval engine and vector store for LLM-powered applications. +* https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/integrations[Integrations]. +Notebooks that demonstrate how to integrate popular services and +projects with Elasticsearch, including OpenAI, Hugging Face, and +LlamaIndex +* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/langchain[Langchain]. +Notebooks that demonstrate how to integrate Elastic with LangChain, a +framework for developing applications powered by language models. diff --git a/docs/guide/getting-started.asciidoc b/docs/guide/getting-started.asciidoc index 1b964e50c..58b6f33a5 100644 --- a/docs/guide/getting-started.asciidoc +++ b/docs/guide/getting-started.asciidoc @@ -70,11 +70,33 @@ This is how you create the `my_index` index: client.indices.create(index="my_index") ---- +Optionally, you can first define the expected types of your features with a +custom mapping. + +[source,py] +---- +mappings = { + "properties": { + "foo": {"type": "text"}, + "bar": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256, + } + }, + }, + } +} + +client.indices.create(index="my_index", mappings=mappings) +---- [discrete] ==== Indexing documents -This is a simple way of indexing a document: +This indexes a document with the index API: [source,py] ---- @@ -88,6 +110,28 @@ client.index( ) ---- +You can also index multiple documents at once with the bulk helper function: + +[source,py] +---- +from elasticsearch import helpers + +def generate_docs(): + for i in range(10): + yield { + "_index": "my_index", + "foo": f"foo {i}", + "bar": "bar", + } + +helpers.bulk(client, generate_docs()) +---- + +These helpers are the recommended way to perform bulk ingestion. While it is +also possible to perform bulk ingestion using `client.bulk` directly, the +helpers handle retries, ingesting chunk by chunk and more. See the +<> page for more details. + [discrete] ==== Getting documents @@ -122,10 +166,14 @@ This is how you can update a document, for example to add a new field: [source,py] ---- -client.update(index="my_index", id="my_document_id", doc={ - "foo": "bar", - "new_field": "new value", -}) +client.update( + index="my_index", + id="my_document_id", + doc={ + "foo": "bar", + "new_field": "new value", + } +) ---- diff --git a/docs/guide/index-custom-title-page.html b/docs/guide/index-custom-title-page.html index b7fd0f405..8c2d03af2 100644 --- a/docs/guide/index-custom-title-page.html +++ b/docs/guide/index-custom-title-page.html @@ -95,6 +95,9 @@

  • Configuring the client
  • +
  • + Using the client with asyncio +
  • @@ -136,7 +139,7 @@

    Integrations
  • - Elasticsearch Python DSL + Python DSL
  • Client helpers diff --git a/docs/guide/index.asciidoc b/docs/guide/index.asciidoc index 5607a9f24..687710626 100644 --- a/docs/guide/index.asciidoc +++ b/docs/guide/index.asciidoc @@ -16,6 +16,8 @@ include::connecting.asciidoc[] include::configuration.asciidoc[] +include::async.asciidoc[] + include::migration.asciidoc[] include::integrations.asciidoc[] From 16596bc5b58111adb226651e664219d530908771 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Tue, 28 Jan 2025 11:08:17 +0000 Subject: [PATCH 2/3] review feedback --- docs/guide/async.asciidoc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/guide/async.asciidoc b/docs/guide/async.asciidoc index ce30bcf41..9f3c04acd 100644 --- a/docs/guide/async.asciidoc +++ b/docs/guide/async.asciidoc @@ -15,11 +15,12 @@ $ python -m pip install elasticsearch aiohttp $ python -m pip install elasticsearch[async] ---- +[discrete] === Getting Started with Async After installation all async API endpoints are available via `~elasticsearch.AsyncElasticsearch` and are used in the same way as -other APIs, just with an extra `await`: +other APIs, with an extra `await`: [source,python] ---- @@ -43,10 +44,13 @@ loop.run_until_complete(main()) All APIs that are available under the sync client are also available under the async client. +https://elasticsearch-py.readthedocs.io/en/latest/async.html#api-reference[Reference documentation] + +[discrete] === ASGI Applications and Elastic APM https://asgi.readthedocs.io[ASGI] (Asynchronous Server Gateway -Interface) is a new way to serve Python web applications making use of +Interface) is a way to serve Python web applications making use of async I/O to achieve better performance. Some examples of ASGI frameworks include FastAPI, Django 3.0+, and Starlette. If you're using one of these frameworks along with Elasticsearch then you should @@ -61,8 +65,12 @@ https://fastapi.tiangolo.com/[FastAPI] and APM tracing there is a https://github.com/elastic/elasticsearch-py/tree/master/examples/fastapi-apm[pre-built example] in the `examples/fastapi-apm` directory. +See also the <> page. + +[discrete] === Frequently Asked Questions +[discrete] ==== ValueError when initializing `AsyncElasticsearch`? If when trying to use `AsyncElasticsearch` you receive @@ -71,6 +79,7 @@ you should ensure that you have `aiohttp` installed in your environment (check with `$ python -m pip freeze | grep aiohttp`). Otherwise, async support won't be available. +[discrete] ==== What about the `elasticsearch-async` package? Previously asyncio was supported separately via the @@ -79,6 +88,7 @@ package. The `elasticsearch-async` package has been deprecated in favor of `AsyncElasticsearch` provided by the `elasticsearch` package in v7.8 and onwards. +[discrete] ==== Receiving 'Unclosed client session / connector' warning? This warning is created by `aiohttp` when an open HTTP connection is @@ -117,6 +127,7 @@ async def main(): You can run this example by saving it to `main.py` and executing `ELASTICSEARCH_URL=http://localhost:9200 uvicorn main:app`. +[discrete] === Async Helpers Async variants of all helpers are available in `elasticsearch.helpers` @@ -125,3 +136,6 @@ are identical to the ones in the sync <> documentation. All async helpers that accept an iterator or generator also accept async iterators and async generators. + +https://elasticsearch-py.readthedocs.io/en/latest/async.html#async-helpers[Reference documentation] + From 891b7332b935a956e0b0ec26c5ddcabb244c25df Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Tue, 28 Jan 2025 11:17:27 +0000 Subject: [PATCH 3/3] unrelated formatting changes --- elasticsearch/dsl/_sync/search.py | 10 ++- elasticsearch/dsl/response/__init__.py | 68 ++++++++++++++----- elasticsearch/dsl/types.py | 4 +- .../helpers/vectorstore/_sync/vectorstore.py | 5 +- examples/dsl/search_as_you_type.py | 7 +- .../test_dsl/_sync/test_index.py | 9 ++- .../test_dsl/_sync/test_search.py | 10 ++- .../test_integration/_sync/test_search.py | 10 ++- 8 files changed, 98 insertions(+), 25 deletions(-) diff --git a/elasticsearch/dsl/_sync/search.py b/elasticsearch/dsl/_sync/search.py index f46364a67..ae826a12f 100644 --- a/elasticsearch/dsl/_sync/search.py +++ b/elasticsearch/dsl/_sync/search.py @@ -16,7 +16,15 @@ # under the License. import contextlib -from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, cast +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Iterator, + List, + Optional, + cast, +) from typing_extensions import Self diff --git a/elasticsearch/dsl/response/__init__.py b/elasticsearch/dsl/response/__init__.py index f6f3d551d..2ae863fff 100644 --- a/elasticsearch/dsl/response/__init__.py +++ b/elasticsearch/dsl/response/__init__.py @@ -53,9 +53,19 @@ class Response(AttrDict[Any], Generic[_R]): """An Elasticsearch search response. - :arg took: (required) - :arg timed_out: (required) - :arg _shards: (required) + :arg took: (required) The number of milliseconds it took Elasticsearch + to run the request. This value is calculated by measuring the time + elapsed between receipt of a request on the coordinating node and + the time at which the coordinating node is ready to send the + response. It includes: * Communication time between the + coordinating node and data nodes * Time the request spends in the + search thread pool, queued for execution * Actual run time It + does not include: * Time needed to send the request to + Elasticsearch * Time needed to serialize the JSON response * Time + needed to send the response to a client + :arg timed_out: (required) If `true`, the request timed out before + completion; returned results may be partial or empty. + :arg _shards: (required) A count of shards used for the request. :arg hits: search results :arg aggregations: aggregation results :arg _clusters: @@ -64,7 +74,11 @@ class Response(AttrDict[Any], Generic[_R]): :arg num_reduce_phases: :arg profile: :arg pit_id: - :arg _scroll_id: + :arg _scroll_id: The identifier for the search and its search context. + You can use this scroll ID with the scroll API to retrieve the + next batch of search results for the request. This property is + returned only if the `scroll` query parameter is specified in the + request. :arg suggest: :arg terminated_early: """ @@ -303,22 +317,42 @@ def __iter__(self) -> Iterator[AggregateResponseType]: # type: ignore[override] class UpdateByQueryResponse(AttrDict[Any], Generic[_R]): """An Elasticsearch update by query response. - :arg batches: - :arg failures: - :arg noops: - :arg deleted: - :arg requests_per_second: - :arg retries: + :arg batches: The number of scroll responses pulled back by the update + by query. + :arg failures: Array of failures if there were any unrecoverable + errors during the process. If this is non-empty then the request + ended because of those failures. Update by query is implemented + using batches. Any failure causes the entire process to end, but + all failures in the current batch are collected into the array. + You can use the `conflicts` option to prevent reindex from ending + when version conflicts occur. + :arg noops: The number of documents that were ignored because the + script used for the update by query returned a noop value for + `ctx.op`. + :arg deleted: The number of documents that were successfully deleted. + :arg requests_per_second: The number of requests per second + effectively run during the update by query. + :arg retries: The number of retries attempted by update by query. + `bulk` is the number of bulk actions retried. `search` is the + number of search actions retried. :arg task: - :arg timed_out: - :arg took: - :arg total: - :arg updated: - :arg version_conflicts: + :arg timed_out: If true, some requests timed out during the update by + query. + :arg took: The number of milliseconds from start to end of the whole + operation. + :arg total: The number of documents that were successfully processed. + :arg updated: The number of documents that were successfully updated. + :arg version_conflicts: The number of version conflicts that the + update by query hit. :arg throttled: - :arg throttled_millis: + :arg throttled_millis: The number of milliseconds the request slept to + conform to `requests_per_second`. :arg throttled_until: - :arg throttled_until_millis: + :arg throttled_until_millis: This field should always be equal to zero + in an _update_by_query response. It only has meaning when using + the task API, where it indicates the next time (in milliseconds + since epoch) a throttled request will be run again in order to + conform to `requests_per_second`. """ _search: "UpdateByQueryBase[_R]" diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index 012defa9a..80332ce32 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -406,9 +406,9 @@ class FieldAndFormat(AttrDict[Any]): A reference to a field with formatting instructions on how to return the value - :arg field: (required) Wildcard pattern. The request returns values + :arg field: (required) A wildcard pattern. The request returns values for field names matching this pattern. - :arg format: Format in which the values are returned. + :arg format: The format in which the values are returned. :arg include_unmapped: """ diff --git a/elasticsearch/helpers/vectorstore/_sync/vectorstore.py b/elasticsearch/helpers/vectorstore/_sync/vectorstore.py index 3c4a0d51a..6a6a5ee2a 100644 --- a/elasticsearch/helpers/vectorstore/_sync/vectorstore.py +++ b/elasticsearch/helpers/vectorstore/_sync/vectorstore.py @@ -22,7 +22,10 @@ from elasticsearch import Elasticsearch from elasticsearch._version import __versionstr__ as lib_version from elasticsearch.helpers import BulkIndexError, bulk -from elasticsearch.helpers.vectorstore import EmbeddingService, RetrievalStrategy +from elasticsearch.helpers.vectorstore import ( + EmbeddingService, + RetrievalStrategy, +) from elasticsearch.helpers.vectorstore._utils import maximal_marginal_relevance logger = logging.getLogger(__name__) diff --git a/examples/dsl/search_as_you_type.py b/examples/dsl/search_as_you_type.py index c1ebc99a4..a70de8ccb 100644 --- a/examples/dsl/search_as_you_type.py +++ b/examples/dsl/search_as_you_type.py @@ -28,7 +28,12 @@ import os from typing import TYPE_CHECKING, Optional -from elasticsearch.dsl import Document, SearchAsYouType, connections, mapped_field +from elasticsearch.dsl import ( + Document, + SearchAsYouType, + connections, + mapped_field, +) from elasticsearch.dsl.query import MultiMatch diff --git a/test_elasticsearch/test_dsl/_sync/test_index.py b/test_elasticsearch/test_dsl/_sync/test_index.py index c6d1b7904..327efa047 100644 --- a/test_elasticsearch/test_dsl/_sync/test_index.py +++ b/test_elasticsearch/test_dsl/_sync/test_index.py @@ -22,7 +22,14 @@ import pytest from pytest import raises -from elasticsearch.dsl import Date, Document, Index, IndexTemplate, Text, analyzer +from elasticsearch.dsl import ( + Date, + Document, + Index, + IndexTemplate, + Text, + analyzer, +) class Post(Document): diff --git a/test_elasticsearch/test_dsl/_sync/test_search.py b/test_elasticsearch/test_dsl/_sync/test_search.py index 04b0ad53e..1fa7da1c7 100644 --- a/test_elasticsearch/test_dsl/_sync/test_search.py +++ b/test_elasticsearch/test_dsl/_sync/test_search.py @@ -21,7 +21,15 @@ import pytest from pytest import raises -from elasticsearch.dsl import Document, EmptySearch, Q, Search, query, types, wrappers +from elasticsearch.dsl import ( + Document, + EmptySearch, + Q, + Search, + query, + types, + wrappers, +) from elasticsearch.dsl.exceptions import IllegalOperation diff --git a/test_elasticsearch/test_dsl/test_integration/_sync/test_search.py b/test_elasticsearch/test_dsl/test_integration/_sync/test_search.py index 54060d311..41dd720a3 100644 --- a/test_elasticsearch/test_dsl/test_integration/_sync/test_search.py +++ b/test_elasticsearch/test_dsl/test_integration/_sync/test_search.py @@ -20,7 +20,15 @@ from pytest import raises from elasticsearch import ApiError, Elasticsearch -from elasticsearch.dsl import Date, Document, Keyword, MultiSearch, Q, Search, Text +from elasticsearch.dsl import ( + Date, + Document, + Keyword, + MultiSearch, + Q, + Search, + Text, +) from elasticsearch.dsl.response import aggs from ..test_data import FLAT_DATA