Expanded type coverage to benchmarks, samples and tests. (#566)

* Renamed json samples to fix duplicate module name.

Signed-off-by: dblock <[email protected]>

* Enabled mypy on all source files.

Signed-off-by: dblock <[email protected]>

* Added missing types.

Signed-off-by: dblock <[email protected]>

* Added CHANGELOG.

Signed-off-by: dblock <[email protected]>

* Move type: ignore to fix untyped decorator makes function untyped.

Signed-off-by: dblock <[email protected]>

* Fix nox -rs lint-3.7.

Signed-off-by: dblock <[email protected]>

* Fixed incorrect import.

Signed-off-by: dblock <[email protected]>

* Fix broken test.

Signed-off-by: dblock <[email protected]>

* Fixed TestBulk::test_bulk_works_with_bytestring_body.

Signed-off-by: dblock <[email protected]>

---------

Signed-off-by: dblock <[email protected]>
This commit is contained in:
Daniel (dB.) Doubrovkine
2023-11-09 10:51:20 -05:00
committed by GitHub
parent dcb79cc322
commit 56c96d7c4f
101 changed files with 1234 additions and 1019 deletions
+1
View File
@@ -24,6 +24,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Generate `cat` client from API specs ([#529](https://github.com/opensearch-project/opensearch-py/pull/529)) - Generate `cat` client from API specs ([#529](https://github.com/opensearch-project/opensearch-py/pull/529))
- Use API generator for all APIs ([#551](https://github.com/opensearch-project/opensearch-py/pull/551)) - Use API generator for all APIs ([#551](https://github.com/opensearch-project/opensearch-py/pull/551))
- Merge `.pyi` type stubs inline ([#563](https://github.com/opensearch-project/opensearch-py/pull/563)) - Merge `.pyi` type stubs inline ([#563](https://github.com/opensearch-project/opensearch-py/pull/563))
- Expanded type coverage to benchmarks, samples and tests ([#566](https://github.com/opensearch-project/opensearch-py/pull/566))
### Deprecated ### Deprecated
- Deprecated point-in-time APIs (list_all_point_in_time, create_point_in_time, delete_point_in_time) and Security Client APIs (health_check and update_audit_config) ([#502](https://github.com/opensearch-project/opensearch-py/pull/502)) - Deprecated point-in-time APIs (list_all_point_in_time, create_point_in_time, delete_point_in_time) and Security Client APIs (health_check and update_audit_config) ([#502](https://github.com/opensearch-project/opensearch-py/pull/502))
### Removed ### Removed
+3 -2
View File
@@ -12,6 +12,7 @@
import asyncio import asyncio
import uuid import uuid
from typing import Any
from opensearchpy import AsyncHttpConnection, AsyncOpenSearch from opensearchpy import AsyncHttpConnection, AsyncOpenSearch
@@ -22,7 +23,7 @@ index_name = "test-index-async"
item_count = 100 item_count = 100
async def index_records(client, item_count) -> None: async def index_records(client: Any, item_count: int) -> None:
await asyncio.gather( await asyncio.gather(
*[ *[
client.index( client.index(
@@ -39,7 +40,7 @@ async def index_records(client, item_count) -> None:
) )
async def test_async(client_count=1, item_count=1): async def test_async(client_count: int = 1, item_count: int = 1) -> None:
clients = [] clients = []
for i in range(client_count): for i in range(client_count):
clients.append( clients.append(
+4 -3
View File
@@ -14,6 +14,7 @@
import logging import logging
import sys import sys
import time import time
from typing import Any
from thread_with_return_value import ThreadWithReturnValue from thread_with_return_value import ThreadWithReturnValue
@@ -36,8 +37,8 @@ handler.setFormatter(formatter)
root.addHandler(handler) root.addHandler(handler)
def get_info(client, request_count): def get_info(client: Any, request_count: int) -> float:
tt = 0 tt: float = 0
for n in range(request_count): for n in range(request_count):
start = time.time() * 1000 start = time.time() * 1000
client.info() client.info()
@@ -46,7 +47,7 @@ def get_info(client, request_count):
return tt return tt
def test(thread_count=1, request_count=1, client_count=1): def test(thread_count: int = 1, request_count: int = 1, client_count: int = 1) -> None:
clients = [] clients = []
for i in range(client_count): for i in range(client_count):
clients.append( clients.append(
+4 -3
View File
@@ -15,6 +15,7 @@ import logging
import sys import sys
import time import time
import uuid import uuid
from typing import Any
from thread_with_return_value import ThreadWithReturnValue from thread_with_return_value import ThreadWithReturnValue
@@ -37,10 +38,10 @@ handler.setFormatter(formatter)
root.addHandler(handler) root.addHandler(handler)
def index_records(client, item_count): def index_records(client: Any, item_count: int) -> Any:
tt = 0 tt = 0
for n in range(10): for n in range(10):
data = [] data: Any = []
for i in range(item_count): for i in range(item_count):
data.append( data.append(
json.dumps({"index": {"_index": index_name, "_id": str(uuid.uuid4())}}) json.dumps({"index": {"_index": index_name, "_id": str(uuid.uuid4())}})
@@ -63,7 +64,7 @@ def index_records(client, item_count):
return tt return tt
def test(thread_count=1, item_count=1, client_count=1): def test(thread_count: int = 1, item_count: int = 1, client_count: int = 1) -> None:
clients = [] clients = []
for i in range(client_count): for i in range(client_count):
clients.append( clients.append(
+15 -4
View File
@@ -10,19 +10,30 @@
from threading import Thread from threading import Thread
from typing import Any, Optional
class ThreadWithReturnValue(Thread): class ThreadWithReturnValue(Thread):
_target: Any
_args: Any
_kwargs: Any
def __init__( def __init__(
self, group=None, target=None, name=None, args=(), kwargs={}, Verbose=None self,
): group: Any = None,
target: Any = None,
name: Optional[str] = None,
args: Any = (),
kwargs: Any = {},
Verbose: Optional[bool] = None,
) -> None:
Thread.__init__(self, group, target, name, args, kwargs) Thread.__init__(self, group, target, name, args, kwargs)
self._return = None self._return = None
def run(self): def run(self) -> None:
if self._target is not None: if self._target is not None:
self._return = self._target(*self._args, **self._kwargs) self._return = self._target(*self._args, **self._kwargs)
def join(self, *args): def join(self, *args: Any) -> Any:
Thread.join(self, *args) Thread.join(self, *args)
return self._return return self._return
+18 -16
View File
@@ -26,9 +26,11 @@
# -- Project information ----------------------------------------------------- # -- Project information -----------------------------------------------------
project = "OpenSearch Python Client" from typing import Any
copyright = "OpenSearch Project Contributors"
author = "OpenSearch Project Contributors" project: str = "OpenSearch Python Client"
copyright: str = "OpenSearch Project Contributors"
author: str = "OpenSearch Project Contributors"
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------
@@ -36,7 +38,7 @@ author = "OpenSearch Project Contributors"
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = [ extensions: Any = [
"sphinx.ext.autodoc", "sphinx.ext.autodoc",
"sphinx_rtd_theme", "sphinx_rtd_theme",
"sphinx.ext.viewcode", "sphinx.ext.viewcode",
@@ -47,12 +49,12 @@ extensions = [
] ]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"] templates_path: Any = ["_templates"]
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path. # This pattern also affects html_static_path and html_extra_path.
exclude_patterns = [] exclude_patterns: Any = []
# -- Options for HTML output ------------------------------------------------- # -- Options for HTML output -------------------------------------------------
@@ -60,31 +62,31 @@ exclude_patterns = []
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
# #
html_theme = "sphinx_rtd_theme" html_theme: str = "sphinx_rtd_theme"
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css". # so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"] html_static_path: Any = ["_static"]
# -- additional settings ------------------------------------------------- # -- additional settings -------------------------------------------------
intersphinx_mapping = { intersphinx_mapping: Any = {
"python": ("https://docs.python.org/3", None), "python": ("https://docs.python.org/3", None),
} }
html_logo = "imgs/OpenSearch.svg" html_logo: str = "imgs/OpenSearch.svg"
# These paths are either relative to html_static_path # These paths are either relative to html_static_path
# or fully qualified paths (eg. https://...) # or fully qualified paths (eg. https://...)
html_css_files = [ html_css_files: Any = [
"css/custom.css", "css/custom.css",
] ]
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = False html_show_sphinx: bool = False
# add github link # add github link
html_context = { html_context: Any = {
"display_github": True, "display_github": True,
"github_user": "opensearch-project", "github_user": "opensearch-project",
"github_repo": "opensearch-py", "github_repo": "opensearch-py",
@@ -94,18 +96,18 @@ html_context = {
# -- autodoc config ------------------------------------------------- # -- autodoc config -------------------------------------------------
# This value controls how to represent typehints. # This value controls how to represent typehints.
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_typehints # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_typehints
autodoc_typehints = "description" autodoc_typehints: str = "description"
# This value selects what content will be inserted into the main body of an autoclass directive. # This value selects what content will be inserted into the main body of an autoclass directive.
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autoclass_content # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autoclass_content
autoclass_content = "both" autoclass_content: str = "both"
# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-add_module_names # https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-add_module_names
# add_module_names = False # add_module_names = False
# The default options for autodoc directives. # The default options for autodoc directives.
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_default_options # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_default_options
autodoc_default_options = { autodoc_default_options: Any = {
# If set, autodoc will generate document for the members of the target module, class or exception. # noqa: E501 # If set, autodoc will generate document for the members of the target module, class or exception. # noqa: E501
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#directive-option-automodule-members # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#directive-option-automodule-members
"members": True, "members": True,
+16 -11
View File
@@ -26,6 +26,8 @@
# under the License. # under the License.
from typing import Any
import nox import nox
SOURCE_FILES = ( SOURCE_FILES = (
@@ -40,16 +42,16 @@ SOURCE_FILES = (
) )
@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]) @nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]) # type: ignore
def test(session) -> None: def test(session: Any) -> None:
session.install(".") session.install(".")
session.install("-r", "dev-requirements.txt") session.install("-r", "dev-requirements.txt")
session.run("python", "setup.py", "test") session.run("python", "setup.py", "test")
@nox.session() @nox.session() # type: ignore
def format(session) -> None: def format(session: Any) -> None:
session.install("black", "isort") session.install("black", "isort")
session.run("isort", "--profile=black", *SOURCE_FILES) session.run("isort", "--profile=black", *SOURCE_FILES)
@@ -59,8 +61,8 @@ def format(session) -> None:
lint(session) lint(session)
@nox.session(python=["3.7"]) @nox.session(python=["3.7"]) # type: ignore
def lint(session) -> None: def lint(session: Any) -> None:
session.install( session.install(
"flake8", "flake8",
"black", "black",
@@ -70,6 +72,9 @@ def lint(session) -> None:
"types-six", "types-six",
"types-simplejson", "types-simplejson",
"types-python-dateutil", "types-python-dateutil",
"types-PyYAML",
"types-mock",
"types-pytz",
) )
session.run("isort", "--check", "--profile=black", *SOURCE_FILES) session.run("isort", "--check", "--profile=black", *SOURCE_FILES)
@@ -82,7 +87,7 @@ def lint(session) -> None:
# Run mypy on the package and then the type examples separately for # Run mypy on the package and then the type examples separately for
# the two different mypy use-cases, ourselves and our users. # the two different mypy use-cases, ourselves and our users.
session.run("mypy", "--strict", "opensearchpy/") session.run("mypy", "--strict", *SOURCE_FILES)
session.run("mypy", "--strict", "test_opensearchpy/test_types/sync_types.py") session.run("mypy", "--strict", "test_opensearchpy/test_types/sync_types.py")
session.run("mypy", "--strict", "test_opensearchpy/test_types/async_types.py") session.run("mypy", "--strict", "test_opensearchpy/test_types/async_types.py")
@@ -93,8 +98,8 @@ def lint(session) -> None:
session.run("mypy", "--strict", "test_opensearchpy/test_types/sync_types.py") session.run("mypy", "--strict", "test_opensearchpy/test_types/sync_types.py")
@nox.session() @nox.session() # type: ignore
def docs(session) -> None: def docs(session: Any) -> None:
session.install(".") session.install(".")
session.install( session.install(
"-rdev-requirements.txt", "sphinx-rtd-theme", "sphinx-autodoc-typehints" "-rdev-requirements.txt", "sphinx-rtd-theme", "sphinx-autodoc-typehints"
@@ -102,8 +107,8 @@ def docs(session) -> None:
session.run("python", "-m", "pip", "install", "sphinx-autodoc-typehints") session.run("python", "-m", "pip", "install", "sphinx-autodoc-typehints")
@nox.session() @nox.session() # type: ignore
def generate(session) -> None: def generate(session: Any) -> None:
session.install("-rdev-requirements.txt") session.install("-rdev-requirements.txt")
session.run("python", "utils/generate-api.py") session.run("python", "utils/generate-api.py")
format(session) format(session)
+1
View File
@@ -256,4 +256,5 @@ __all__ = [
"AsyncTransport", "AsyncTransport",
"AsyncOpenSearch", "AsyncOpenSearch",
"AsyncHttpConnection", "AsyncHttpConnection",
"__versionstr__",
] ]
+6 -8
View File
@@ -10,7 +10,7 @@
import collections.abc as collections_abc import collections.abc as collections_abc
from fnmatch import fnmatch from fnmatch import fnmatch
from typing import Any, Optional, Sequence, Tuple, Type from typing import Any, Optional, Tuple, Type
from six import add_metaclass from six import add_metaclass
@@ -128,9 +128,7 @@ class AsyncDocument(ObjectBase):
) )
@classmethod @classmethod
def search( def search(cls, using: Any = None, index: Any = None) -> AsyncSearch:
cls, using: Optional[AsyncOpenSearch] = None, index: Optional[str] = None
) -> AsyncSearch:
""" """
Create an :class:`~opensearchpy.AsyncSearch` instance that will search Create an :class:`~opensearchpy.AsyncSearch` instance that will search
over this ``Document``. over this ``Document``.
@@ -142,9 +140,9 @@ class AsyncDocument(ObjectBase):
@classmethod @classmethod
async def get( # type: ignore async def get( # type: ignore
cls, cls,
id: str, id: Any,
using: Optional[AsyncOpenSearch] = None, using: Any = None,
index: Optional[str] = None, index: Any = None,
**kwargs: Any, **kwargs: Any,
) -> Any: ) -> Any:
""" """
@@ -189,7 +187,7 @@ class AsyncDocument(ObjectBase):
@classmethod @classmethod
async def mget( async def mget(
cls, cls,
docs: Sequence[str], docs: Any,
using: Optional[AsyncOpenSearch] = None, using: Optional[AsyncOpenSearch] = None,
index: Optional[str] = None, index: Optional[str] = None,
raise_on_error: Optional[bool] = True, raise_on_error: Optional[bool] = True,
+1 -1
View File
@@ -59,7 +59,7 @@ class AsyncIndexTemplate(object):
class AsyncIndex(object): class AsyncIndex(object):
def __init__(self, name: Any, using: str = "default") -> None: def __init__(self, name: Any, using: Any = "default") -> None:
""" """
:arg name: name of the index :arg name: name of the index
:arg using: connection alias to use, defaults to ``'default'`` :arg using: connection alias to use, defaults to ``'default'``
+1 -1
View File
@@ -69,7 +69,7 @@ class AsyncConnection(Connection):
class AIOHttpConnection(AsyncConnection): class AIOHttpConnection(AsyncConnection):
session: Optional[aiohttp.ClientSession] session: aiohttp.ClientSession
ssl_assert_fingerprint: Optional[str] ssl_assert_fingerprint: Optional[str]
def __init__( def __init__(
+5 -5
View File
@@ -32,7 +32,7 @@ import base64
import weakref import weakref
from datetime import date, datetime from datetime import date, datetime
from functools import wraps from functools import wraps
from typing import Any, Callable from typing import Any, Callable, Optional
from opensearchpy.serializer import Serializer from opensearchpy.serializer import Serializer
@@ -185,17 +185,17 @@ def query_params(*opensearch_query_params: Any) -> Callable: # type: ignore
return _wrapper return _wrapper
def _bulk_body(serializer: Serializer, body: str) -> str: def _bulk_body(serializer: Optional[Serializer], body: Any) -> Any:
# if not passed in a string, serialize items and join by newline # if not passed in a string, serialize items and join by newline
if not isinstance(body, string_types): if not isinstance(body, string_types):
body = "\n".join(map(serializer.dumps, body)) body = "\n".join(map(serializer.dumps, body)) # type: ignore
# bulk body must end with a newline # bulk body must end with a newline
if isinstance(body, bytes): if isinstance(body, bytes):
if not body.endswith(b"\n"): if not body.endswith(b"\n"):
body += b"\n" body += b"\n"
elif isinstance(body, string_types) and not body.endswith("\n"): elif isinstance(body, string_types) and not body.endswith("\n"): # type: ignore
body += "\n" body += "\n" # type: ignore
return body return body
@@ -18,6 +18,8 @@ from opensearchpy.serializer import serializer
class AsyncConnections(object): class AsyncConnections(object):
_conns: Any
""" """
Class responsible for holding connections to different clusters. Used as a Class responsible for holding connections to different clusters. Used as a
singleton in this module. singleton in this module.
+3 -3
View File
@@ -124,7 +124,7 @@ class ConnectionPool(object):
connections: Any connections: Any
orig_connections: Tuple[Connection, ...] orig_connections: Tuple[Connection, ...]
dead: Any dead: Any
dead_count: Dict[Connection, int] dead_count: Dict[Any, int]
dead_timeout: float dead_timeout: float
timeout_cutoff: int timeout_cutoff: int
selector: Any selector: Any
@@ -173,7 +173,7 @@ class ConnectionPool(object):
self.selector = selector_class(dict(connections)) # type: ignore self.selector = selector_class(dict(connections)) # type: ignore
def mark_dead(self, connection: Connection, now: Optional[float] = None) -> None: def mark_dead(self, connection: Any, now: Optional[float] = None) -> None:
""" """
Mark the connection as dead (failed). Remove it from the live pool and Mark the connection as dead (failed). Remove it from the live pool and
put it on a timeout. put it on a timeout.
@@ -203,7 +203,7 @@ class ConnectionPool(object):
timeout, timeout,
) )
def mark_live(self, connection: Connection) -> None: def mark_live(self, connection: Any) -> None:
""" """
Mark connection as healthy after a resurrection. Resets the fail Mark connection as healthy after a resurrection. Resets the fail
counter for the connection. counter for the connection.
+5 -5
View File
@@ -503,12 +503,12 @@ def parallel_bulk(
def scan( def scan(
client: Any, client: Any,
query: Any = None, query: Any = None,
scroll: str = "5m", scroll: Optional[str] = "5m",
raise_on_error: bool = True, raise_on_error: Optional[bool] = True,
preserve_order: bool = False, preserve_order: Optional[bool] = False,
size: int = 1000, size: Optional[int] = 1000,
request_timeout: Optional[float] = None, request_timeout: Optional[float] = None,
clear_scroll: bool = True, clear_scroll: Optional[bool] = True,
scroll_kwargs: Any = None, scroll_kwargs: Any = None,
**kwargs: Any **kwargs: Any
) -> Any: ) -> Any:
+12 -4
View File
@@ -8,7 +8,7 @@
# Modifications Copyright OpenSearch Contributors. See # Modifications Copyright OpenSearch Contributors. See
# GitHub history for details. # GitHub history for details.
from typing import Dict, Union from typing import Any, Dict, Optional, Union
class AWSV4SignerAsyncAuth: class AWSV4SignerAsyncAuth:
@@ -16,7 +16,7 @@ class AWSV4SignerAsyncAuth:
AWS V4 Request Signer for Async Requests. AWS V4 Request Signer for Async Requests.
""" """
def __init__(self, credentials, region: str, service: str = "es") -> None: # type: ignore def __init__(self, credentials: Any, region: str, service: str = "es") -> None:
if not credentials: if not credentials:
raise ValueError("Credentials cannot be empty") raise ValueError("Credentials cannot be empty")
self.credentials = credentials self.credentials = credentials
@@ -30,12 +30,20 @@ class AWSV4SignerAsyncAuth:
self.service = service self.service = service
def __call__( def __call__(
self, method: str, url: str, query_string: str, body: Union[str, bytes] self,
method: str,
url: str,
query_string: Optional[str] = None,
body: Optional[Union[str, bytes]] = None,
) -> Dict[str, str]: ) -> Dict[str, str]:
return self._sign_request(method, url, query_string, body) return self._sign_request(method, url, query_string, body)
def _sign_request( def _sign_request(
self, method: str, url: str, query_string: str, body: Union[str, bytes] self,
method: str,
url: str,
query_string: Optional[str],
body: Optional[Union[str, bytes]],
) -> Dict[str, str]: ) -> Dict[str, str]:
""" """
This method helps in signing the request by injecting the required headers. This method helps in signing the request by injecting the required headers.
+1 -3
View File
@@ -268,9 +268,7 @@ class Date(Field):
name: Optional[str] = "date" name: Optional[str] = "date"
_coerce: bool = True _coerce: bool = True
def __init__( def __init__(self, default_timezone: Any = None, *args: Any, **kwargs: Any) -> None:
self, default_timezone: None = None, *args: Any, **kwargs: Any
) -> None:
""" """
:arg default_timezone: timezone that will be automatically used for tz-naive values :arg default_timezone: timezone that will be automatically used for tz-naive values
May be instance of `datetime.tzinfo` or string containing TZ offset May be instance of `datetime.tzinfo` or string containing TZ offset
+1 -1
View File
@@ -78,7 +78,7 @@ class IndexTemplate(object):
class Index(object): class Index(object):
def __init__(self, name: Any, using: str = "default") -> None: def __init__(self, name: Any, using: Any = "default") -> None:
""" """
:arg name: name of the index :arg name: name of the index
:arg using: connection alias to use, defaults to ``'default'`` :arg using: connection alias to use, defaults to ``'default'``
+5 -3
View File
@@ -31,12 +31,11 @@ from typing import Any, Optional
# 'SF' looks unused but the test suite assumes it's available # 'SF' looks unused but the test suite assumes it's available
# from this module so others are liable to do so as well. # from this module so others are liable to do so as well.
from ..helpers.function import SF # noqa: F401 from ..helpers.function import SF, ScoreFunction
from ..helpers.function import ScoreFunction
from .utils import DslBase from .utils import DslBase
def Q(name_or_query: str = "match_all", **params: Any) -> Any: def Q(name_or_query: Any = "match_all", **params: Any) -> Any:
# {"match": {"title": "python"}} # {"match": {"title": "python"}}
if isinstance(name_or_query, collections_abc.Mapping): if isinstance(name_or_query, collections_abc.Mapping):
if params: if params:
@@ -521,3 +520,6 @@ class ParentId(Query):
class Wrapper(Query): class Wrapper(Query):
name = "wrapper" name = "wrapper"
__all__ = ["SF"]
+3
View File
@@ -864,3 +864,6 @@ class MultiSearch(Request):
self._response = out self._response = out
return self._response return self._response
__all__ = ["Q"]
+9 -7
View File
@@ -26,11 +26,9 @@
# under the License. # under the License.
# type: ignore
import os import os
import time import time
from typing import Any, Tuple from typing import Any
from unittest import SkipTest, TestCase from unittest import SkipTest, TestCase
import opensearchpy.client import opensearchpy.client
@@ -52,7 +50,7 @@ def get_test_client(nowait: bool = False, **kwargs: Any) -> OpenSearch:
) )
kw.update(kwargs) kw.update(kwargs)
client = OpenSearch(OPENSEARCH_URL, **kw) client = OpenSearch(OPENSEARCH_URL, **kw) # type: ignore
# wait for yellow status # wait for yellow status
for _ in range(1 if nowait else 100): for _ in range(1 if nowait else 100):
@@ -67,6 +65,8 @@ def get_test_client(nowait: bool = False, **kwargs: Any) -> OpenSearch:
class OpenSearchTestCase(TestCase): class OpenSearchTestCase(TestCase):
client: Any
@staticmethod @staticmethod
def _get_client() -> OpenSearch: def _get_client() -> OpenSearch:
return get_test_client() return get_test_client()
@@ -86,20 +86,20 @@ class OpenSearchTestCase(TestCase):
) )
self.client.indices.delete_template(name="*", ignore=404) self.client.indices.delete_template(name="*", ignore=404)
def opensearch_version(self) -> Tuple[int, ...]: def opensearch_version(self) -> Any:
if not hasattr(self, "_opensearch_version"): if not hasattr(self, "_opensearch_version"):
self._opensearch_version = opensearch_version(self.client) self._opensearch_version = opensearch_version(self.client)
return self._opensearch_version return self._opensearch_version
def _get_version(version_string: str) -> Tuple[int, ...]: def _get_version(version_string: str) -> Any:
if "." not in version_string: if "." not in version_string:
return () return ()
version = version_string.strip().split(".") version = version_string.strip().split(".")
return tuple(int(v) if v.isdigit() else 999 for v in version) return tuple(int(v) if v.isdigit() else 999 for v in version)
def opensearch_version(client: opensearchpy.client.OpenSearch) -> Tuple[int, int, int]: def opensearch_version(client: opensearchpy.client.OpenSearch) -> Any:
return _get_version(client.info()["version"]["number"]) return _get_version(client.info()["version"]["number"])
@@ -111,3 +111,5 @@ else:
verify_certs=False, verify_certs=False,
) )
OPENSEARCH_VERSION = opensearch_version(client) OPENSEARCH_VERSION = opensearch_version(client)
__all__ = ["OpenSearchTestCase"]
+3 -1
View File
@@ -284,7 +284,7 @@ class DslBase(object):
"DSL class `{}` does not exist in {}.".format(name, cls._type_name) "DSL class `{}` does not exist in {}.".format(name, cls._type_name)
) )
def __init__(self, _expand__to_dot: bool = EXPAND__TO_DOT, **params: Any) -> None: def __init__(self, _expand__to_dot: Any = EXPAND__TO_DOT, **params: Any) -> None:
self._params = {} self._params = {}
for pname, pvalue in iteritems(params): for pname, pvalue in iteritems(params):
if "__" in pname and _expand__to_dot: if "__" in pname and _expand__to_dot:
@@ -438,6 +438,8 @@ class HitMeta(AttrDict):
class ObjectBase(AttrDict): class ObjectBase(AttrDict):
_doc_type: Any
def __init__(self, meta: Any = None, **kwargs: Any) -> None: def __init__(self, meta: Any = None, **kwargs: Any) -> None:
meta = meta or {} meta = meta or {}
for k in list(kwargs): for k in list(kwargs):
+1 -1
View File
@@ -373,7 +373,7 @@ class Transport(object):
method: str, method: str,
url: str, url: str,
params: Optional[Mapping[str, Any]] = None, params: Optional[Mapping[str, Any]] = None,
body: Optional[bytes] = None, body: Any = None,
timeout: Optional[Union[int, float]] = None, timeout: Optional[Union[int, float]] = None,
ignore: Collection[int] = (), ignore: Collection[int] = (),
headers: Optional[Mapping[str, str]] = None, headers: Optional[Mapping[str, str]] = None,
+2 -1
View File
@@ -12,6 +12,7 @@
import os import os
from typing import Any
from opensearchpy import OpenSearch from opensearchpy import OpenSearch
@@ -45,7 +46,7 @@ if not client.indices.exists(index_name):
) )
# index data # index data
data = [] data: Any = []
for i in range(100): for i in range(100):
data.append({"index": {"_index": index_name, "_id": i}}) data.append({"index": {"_index": index_name, "_id": i}})
data.append({"value": i}) data.append({"value": i})
+1 -1
View File
@@ -16,7 +16,7 @@ import asyncio
from opensearchpy import AsyncOpenSearch from opensearchpy import AsyncOpenSearch
async def main(): async def main() -> None:
# connect to OpenSearch # connect to OpenSearch
host = "localhost" host = "localhost"
port = 9200 port = 9200
@@ -16,7 +16,7 @@ import asyncio
from opensearchpy import AsyncOpenSearch from opensearchpy import AsyncOpenSearch
async def main(): async def main() -> None:
# connect to OpenSearch # connect to OpenSearch
host = "localhost" host = "localhost"
port = 9200 port = 9200
+1 -1
View File
@@ -18,7 +18,7 @@ import random
from opensearchpy import AsyncHttpConnection, AsyncOpenSearch, helpers from opensearchpy import AsyncHttpConnection, AsyncOpenSearch, helpers
async def main(): async def main() -> None:
# connect to an instance of OpenSearch # connect to an instance of OpenSearch
host = os.getenv("HOST", default="localhost") host = os.getenv("HOST", default="localhost")
port = int(os.getenv("PORT", 9200)) port = int(os.getenv("PORT", 9200))
+3 -1
View File
@@ -11,10 +11,11 @@
import json import json
import threading import threading
from http.server import BaseHTTPRequestHandler, HTTPServer from http.server import BaseHTTPRequestHandler, HTTPServer
from typing import Any
class TestHTTPRequestHandler(BaseHTTPRequestHandler): class TestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self): def do_GET(self) -> None:
headers = self.headers headers = self.headers
if self.path == "/redirect": if self.path == "/redirect":
@@ -40,6 +41,7 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
class TestHTTPServer(HTTPServer): class TestHTTPServer(HTTPServer):
__test__ = False __test__ = False
_server_thread: Any
def __init__(self, host: str = "localhost", port: int = 8080) -> None: def __init__(self, host: str = "localhost", port: int = 8080) -> None:
super().__init__((host, port), TestHTTPRequestHandler) super().__init__((host, port), TestHTTPRequestHandler)
+3 -2
View File
@@ -37,6 +37,7 @@ import subprocess
import sys import sys
from os import environ from os import environ
from os.path import abspath, dirname, exists, join, pardir from os.path import abspath, dirname, exists, join, pardir
from typing import Any
def fetch_opensearch_repo() -> None: def fetch_opensearch_repo() -> None:
@@ -88,8 +89,8 @@ def fetch_opensearch_repo() -> None:
subprocess.check_call("cd %s && git fetch origin %s" % (repo_path, sha), shell=True) subprocess.check_call("cd %s && git fetch origin %s" % (repo_path, sha), shell=True)
def run_all(argv: None = None) -> None: def run_all(argv: Any = None) -> None:
sys.exitfunc = lambda: sys.stderr.write("Shutting down....\n") sys.exitfunc = lambda: sys.stderr.write("Shutting down....\n") # type: ignore
# fetch yaml tests anywhere that's not GitHub Actions # fetch yaml tests anywhere that's not GitHub Actions
if "GITHUB_ACTION" not in environ: if "GITHUB_ACTION" not in environ:
fetch_opensearch_repo() fetch_opensearch_repo()
+24 -18
View File
@@ -32,6 +32,7 @@ import json
import ssl import ssl
import warnings import warnings
from platform import python_version from platform import python_version
from typing import Any
import aiohttp import aiohttp
import pytest import pytest
@@ -52,29 +53,29 @@ pytestmark: MarkDecorator = pytest.mark.asyncio
class TestAIOHttpConnection: class TestAIOHttpConnection:
async def _get_mock_connection( async def _get_mock_connection(
self, self,
connection_params={}, connection_params: Any = {},
response_code: int = 200, response_code: int = 200,
response_body: bytes = b"{}", response_body: bytes = b"{}",
response_headers={}, response_headers: Any = {},
): ) -> Any:
con = AIOHttpConnection(**connection_params) con = AIOHttpConnection(**connection_params)
await con._create_aiohttp_session() await con._create_aiohttp_session()
def _dummy_request(*args, **kwargs): def _dummy_request(*args: Any, **kwargs: Any) -> Any:
class DummyResponse: class DummyResponse:
async def __aenter__(self, *_, **__): async def __aenter__(self, *_: Any, **__: Any) -> Any:
return self return self
async def __aexit__(self, *_, **__): async def __aexit__(self, *_: Any, **__: Any) -> None:
pass pass
async def text(self): async def text(self) -> Any:
return response_body.decode("utf-8", "surrogatepass") return response_body.decode("utf-8", "surrogatepass")
dummy_response = DummyResponse() dummy_response: Any = DummyResponse()
dummy_response.headers = CIMultiDict(**response_headers) dummy_response.headers = CIMultiDict(**response_headers)
dummy_response.status = response_code dummy_response.status = response_code
_dummy_request.call_args = (args, kwargs) _dummy_request.call_args = (args, kwargs) # type: ignore
return dummy_response return dummy_response
con.session.request = _dummy_request con.session.request = _dummy_request
@@ -231,6 +232,7 @@ class TestAIOHttpConnection:
assert w == [], str([x.message for x in w]) assert w == [], str([x.message for x in w])
async def test_warns_if_using_non_default_ssl_kwargs_with_ssl_context(self) -> None: async def test_warns_if_using_non_default_ssl_kwargs_with_ssl_context(self) -> None:
kwargs: Any
for kwargs in ( for kwargs in (
{"ssl_show_warn": False}, {"ssl_show_warn": False},
{"ssl_show_warn": True}, {"ssl_show_warn": True},
@@ -253,26 +255,28 @@ class TestAIOHttpConnection:
) )
@patch("ssl.SSLContext.load_verify_locations") @patch("ssl.SSLContext.load_verify_locations")
async def test_uses_given_ca_certs(self, load_verify_locations, tmp_path) -> None: async def test_uses_given_ca_certs(
self, load_verify_locations: Any, tmp_path: Any
) -> None:
path = tmp_path / "ca_certs.pem" path = tmp_path / "ca_certs.pem"
path.touch() path.touch()
AIOHttpConnection(use_ssl=True, ca_certs=str(path)) AIOHttpConnection(use_ssl=True, ca_certs=str(path))
load_verify_locations.assert_called_once_with(cafile=str(path)) load_verify_locations.assert_called_once_with(cafile=str(path))
@patch("ssl.SSLContext.load_verify_locations") @patch("ssl.SSLContext.load_verify_locations")
async def test_uses_default_ca_certs(self, load_verify_locations) -> None: async def test_uses_default_ca_certs(self, load_verify_locations: Any) -> None:
AIOHttpConnection(use_ssl=True) AIOHttpConnection(use_ssl=True)
load_verify_locations.assert_called_once_with( load_verify_locations.assert_called_once_with(
cafile=Connection.default_ca_certs() cafile=Connection.default_ca_certs()
) )
@patch("ssl.SSLContext.load_verify_locations") @patch("ssl.SSLContext.load_verify_locations")
async def test_uses_no_ca_certs(self, load_verify_locations) -> None: async def test_uses_no_ca_certs(self, load_verify_locations: Any) -> None:
AIOHttpConnection(use_ssl=True, verify_certs=False) AIOHttpConnection(use_ssl=True, verify_certs=False)
load_verify_locations.assert_not_called() load_verify_locations.assert_not_called()
async def test_trust_env(self) -> None: async def test_trust_env(self) -> None:
con = AIOHttpConnection(trust_env=True) con: Any = AIOHttpConnection(trust_env=True)
await con._create_aiohttp_session() await con._create_aiohttp_session()
assert con._trust_env is True assert con._trust_env is True
@@ -286,7 +290,7 @@ class TestAIOHttpConnection:
assert con.session.trust_env is False assert con.session.trust_env is False
@patch("opensearchpy.connection.base.logger") @patch("opensearchpy.connection.base.logger")
async def test_uncompressed_body_logged(self, logger) -> None: async def test_uncompressed_body_logged(self, logger: Any) -> None:
con = await self._get_mock_connection(connection_params={"http_compress": True}) con = await self._get_mock_connection(connection_params={"http_compress": True})
await con.perform_request("GET", "/", body=b'{"example": "body"}') await con.perform_request("GET", "/", body=b'{"example": "body"}')
@@ -302,11 +306,11 @@ class TestAIOHttpConnection:
status, headers, data = await con.perform_request("GET", "/") status, headers, data = await con.perform_request("GET", "/")
assert u"你好\uda6a" == data # fmt: skip assert u"你好\uda6a" == data # fmt: skip
@pytest.mark.parametrize("exception_cls", reraise_exceptions) @pytest.mark.parametrize("exception_cls", reraise_exceptions) # type: ignore
async def test_recursion_error_reraised(self, exception_cls) -> None: async def test_recursion_error_reraised(self, exception_cls: Any) -> None:
conn = AIOHttpConnection() conn = AIOHttpConnection()
def request_raise(*_, **__): def request_raise(*_: Any, **__: Any) -> Any:
raise exception_cls("Wasn't modified!") raise exception_cls("Wasn't modified!")
await conn._create_aiohttp_session() await conn._create_aiohttp_session()
@@ -334,6 +338,8 @@ class TestAIOHttpConnection:
class TestConnectionHttpServer: class TestConnectionHttpServer:
"""Tests the HTTP connection implementations against a live server E2E""" """Tests the HTTP connection implementations against a live server E2E"""
server: Any
@classmethod @classmethod
def setup_class(cls) -> None: def setup_class(cls) -> None:
# Start server # Start server
@@ -345,7 +351,7 @@ class TestConnectionHttpServer:
# Stop server # Stop server
cls.server.stop() cls.server.stop()
async def httpserver(self, conn, **kwargs): async def httpserver(self, conn: Any, **kwargs: Any) -> Any:
status, headers, data = await conn.perform_request("GET", "/", **kwargs) status, headers, data = await conn.perform_request("GET", "/", **kwargs)
data = json.loads(data) data = json.loads(data)
return (status, data) return (status, data)
@@ -9,6 +9,8 @@
# GitHub history for details. # GitHub history for details.
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
from mock import Mock from mock import Mock
@@ -19,18 +21,18 @@ from opensearchpy.connection.async_connections import add_connection, async_conn
pytestmark: MarkDecorator = pytest.mark.asyncio pytestmark: MarkDecorator = pytest.mark.asyncio
@fixture @fixture # type: ignore
async def mock_client(dummy_response): async def mock_client(dummy_response: Any) -> Any:
client = Mock() client = Mock()
client.search.return_value = dummy_response client.search.return_value = dummy_response
await add_connection("mock", client) await add_connection("mock", client)
yield client yield client
async_connections._conn = {} async_connections._conns = {}
async_connections._kwargs = {} async_connections._kwargs = {}
@fixture @fixture # type: ignore
def dummy_response(): def dummy_response() -> Any:
return { return {
"_shards": {"failed": 0, "successful": 10, "total": 10}, "_shards": {"failed": 0, "successful": 10, "total": 10},
"hits": { "hits": {
@@ -78,8 +80,8 @@ def dummy_response():
} }
@fixture @fixture # type: ignore
def aggs_search(): def aggs_search() -> Any:
from opensearchpy._async.helpers.search import AsyncSearch from opensearchpy._async.helpers.search import AsyncSearch
s = AsyncSearch(index="flat-git") s = AsyncSearch(index="flat-git")
@@ -93,8 +95,8 @@ def aggs_search():
return s return s
@fixture @fixture # type: ignore
def aggs_data(): def aggs_data() -> Any:
return { return {
"took": 4, "took": 4,
"timed_out": False, "timed_out": False,
@@ -15,6 +15,7 @@ import ipaddress
import pickle import pickle
from datetime import datetime from datetime import datetime
from hashlib import sha256 from hashlib import sha256
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -31,25 +32,25 @@ pytestmark: MarkDecorator = pytest.mark.asyncio
class MyInner(InnerDoc): class MyInner(InnerDoc):
old_field = field.Text() old_field: Any = field.Text()
class MyDoc(document.AsyncDocument): class MyDoc(document.AsyncDocument):
title = field.Keyword() title: Any = field.Keyword()
name = field.Text() name: Any = field.Text()
created_at = field.Date() created_at: Any = field.Date()
inner = field.Object(MyInner) inner: Any = field.Object(MyInner)
class MySubDoc(MyDoc): class MySubDoc(MyDoc):
name = field.Keyword() name: Any = field.Keyword()
class Index: class Index:
name = "default-index" name = "default-index"
class MyDoc2(document.AsyncDocument): class MyDoc2(document.AsyncDocument):
extra = field.Long() extra: Any = field.Long()
class MyMultiSubDoc(MyDoc2, MySubDoc): class MyMultiSubDoc(MyDoc2, MySubDoc):
@@ -57,19 +58,19 @@ class MyMultiSubDoc(MyDoc2, MySubDoc):
class Comment(InnerDoc): class Comment(InnerDoc):
title = field.Text() title: Any = field.Text()
tags = field.Keyword(multi=True) tags: Any = field.Keyword(multi=True)
class DocWithNested(document.AsyncDocument): class DocWithNested(document.AsyncDocument):
comments = field.Nested(Comment) comments: Any = field.Nested(Comment)
class Index: class Index:
name = "test-doc-with-nested" name = "test-doc-with-nested"
class SimpleCommit(document.AsyncDocument): class SimpleCommit(document.AsyncDocument):
files = field.Text(multi=True) files: Any = field.Text(multi=True)
class Index: class Index:
name = "test-git" name = "test-git"
@@ -80,48 +81,54 @@ class Secret(str):
class SecretField(field.CustomField): class SecretField(field.CustomField):
builtin_type = "text" builtin_type: Any = "text"
def _serialize(self, data): def _serialize(self, data: Any) -> Any:
return codecs.encode(data, "rot_13") return codecs.encode(data, "rot_13")
def _deserialize(self, data): def _deserialize(self, data: Any) -> Any:
if isinstance(data, Secret): if isinstance(data, Secret):
return data return data
return Secret(codecs.decode(data, "rot_13")) return Secret(codecs.decode(data, "rot_13"))
class SecretDoc(document.AsyncDocument): class SecretDoc(document.AsyncDocument):
title = SecretField(index="no") title: Any = SecretField(index="no")
class Index: class Index:
name = "test-secret-doc" name = "test-secret-doc"
class NestedSecret(document.AsyncDocument): class NestedSecret(document.AsyncDocument):
secrets = field.Nested(SecretDoc) secrets: Any = field.Nested(SecretDoc)
class Index: class Index:
name = "test-nested-secret" name = "test-nested-secret"
_index: Any
class OptionalObjectWithRequiredField(document.AsyncDocument): class OptionalObjectWithRequiredField(document.AsyncDocument):
comments = field.Nested(properties={"title": field.Keyword(required=True)}) comments: Any = field.Nested(properties={"title": field.Keyword(required=True)})
class Index: class Index:
name = "test-required" name = "test-required"
_index: Any
class Host(document.AsyncDocument): class Host(document.AsyncDocument):
ip = field.Ip() ip: Any = field.Ip()
class Index: class Index:
name = "test-host" name = "test-host"
_index: Any
async def test_range_serializes_properly() -> None: async def test_range_serializes_properly() -> None:
class D(document.AsyncDocument): class D(document.AsyncDocument):
lr = field.LongRange() lr: Any = field.LongRange()
d = D(lr=Range(lt=42)) d = D(lr=Range(lt=42))
assert 40 in d.lr assert 40 in d.lr
@@ -200,7 +207,7 @@ async def test_assigning_attrlist_to_field() -> None:
async def test_optional_inner_objects_are_not_validated_if_missing() -> None: async def test_optional_inner_objects_are_not_validated_if_missing() -> None:
d = OptionalObjectWithRequiredField() d: Any = OptionalObjectWithRequiredField()
assert d.full_clean() is None assert d.full_clean() is None
@@ -253,13 +260,15 @@ async def test_null_value_for_object() -> None:
assert d.inner is None assert d.inner is None
async def test_inherited_doc_types_can_override_index(): async def test_inherited_doc_types_can_override_index() -> None:
class MyDocDifferentIndex(MySubDoc): class MyDocDifferentIndex(MySubDoc):
_index: Any
class Index: class Index:
name = "not-default-index" name: Any = "not-default-index"
settings = {"number_of_replicas": 0} settings: Any = {"number_of_replicas": 0}
aliases = {"a": {}} aliases: Any = {"a": {}}
analyzers = [analyzer("my_analizer", tokenizer="keyword")] analyzers: Any = [analyzer("my_analizer", tokenizer="keyword")]
assert MyDocDifferentIndex._index._name == "not-default-index" assert MyDocDifferentIndex._index._name == "not-default-index"
assert MyDocDifferentIndex()._get_index() == "not-default-index" assert MyDocDifferentIndex()._get_index() == "not-default-index"
@@ -285,7 +294,7 @@ async def test_inherited_doc_types_can_override_index():
} }
async def test_to_dict_with_meta(): async def test_to_dict_with_meta() -> None:
d = MySubDoc(title="hello") d = MySubDoc(title="hello")
d.meta.routing = "some-parent" d.meta.routing = "some-parent"
@@ -296,7 +305,7 @@ async def test_to_dict_with_meta():
} == d.to_dict(True) } == d.to_dict(True)
async def test_to_dict_with_meta_includes_custom_index(): async def test_to_dict_with_meta_includes_custom_index() -> None:
d = MySubDoc(title="hello") d = MySubDoc(title="hello")
d.meta.index = "other-index" d.meta.index = "other-index"
@@ -340,7 +349,7 @@ async def test_meta_is_accessible_even_on_empty_doc() -> None:
d.meta d.meta
async def test_meta_field_mapping(): async def test_meta_field_mapping() -> None:
class User(document.AsyncDocument): class User(document.AsyncDocument):
username = field.Text() username = field.Text()
@@ -372,17 +381,17 @@ async def test_multi_value_fields() -> None:
async def test_docs_with_properties() -> None: async def test_docs_with_properties() -> None:
class User(document.AsyncDocument): class User(document.AsyncDocument):
pwd_hash = field.Text() pwd_hash: Any = field.Text()
def check_password(self, pwd): def check_password(self, pwd: Any) -> Any:
return sha256(pwd).hexdigest() == self.pwd_hash return sha256(pwd).hexdigest() == self.pwd_hash
@property @property
def password(self): def password(self) -> Any:
raise AttributeError("readonly") raise AttributeError("readonly")
@password.setter @password.setter
def password(self, pwd): def password(self, pwd: Any) -> None:
self.pwd_hash = sha256(pwd).hexdigest() self.pwd_hash = sha256(pwd).hexdigest()
u = User(pwd_hash=sha256(b"secret").hexdigest()) u = User(pwd_hash=sha256(b"secret").hexdigest())
@@ -424,8 +433,8 @@ async def test_nested_defaults_to_list_and_can_be_updated() -> None:
assert {"comments": [{"title": "hello World!"}]} == md.to_dict() assert {"comments": [{"title": "hello World!"}]} == md.to_dict()
async def test_to_dict_is_recursive_and_can_cope_with_multi_values(): async def test_to_dict_is_recursive_and_can_cope_with_multi_values() -> None:
md = MyDoc(name=["a", "b", "c"]) md: Any = MyDoc(name=["a", "b", "c"])
md.inner = [MyInner(old_field="of1"), MyInner(old_field="of2")] md.inner = [MyInner(old_field="of1"), MyInner(old_field="of2")]
assert isinstance(md.inner[0], MyInner) assert isinstance(md.inner[0], MyInner)
@@ -437,12 +446,12 @@ async def test_to_dict_is_recursive_and_can_cope_with_multi_values():
async def test_to_dict_ignores_empty_collections() -> None: async def test_to_dict_ignores_empty_collections() -> None:
md = MySubDoc(name="", address={}, count=0, valid=False, tags=[]) md: Any = MySubDoc(name="", address={}, count=0, valid=False, tags=[])
assert {"name": "", "count": 0, "valid": False} == md.to_dict() assert {"name": "", "count": 0, "valid": False} == md.to_dict()
async def test_declarative_mapping_definition(): async def test_declarative_mapping_definition() -> None:
assert issubclass(MyDoc, document.AsyncDocument) assert issubclass(MyDoc, document.AsyncDocument)
assert hasattr(MyDoc, "_doc_type") assert hasattr(MyDoc, "_doc_type")
assert { assert {
@@ -455,7 +464,7 @@ async def test_declarative_mapping_definition():
} == MyDoc._doc_type.mapping.to_dict() } == MyDoc._doc_type.mapping.to_dict()
async def test_you_can_supply_own_mapping_instance(): async def test_you_can_supply_own_mapping_instance() -> None:
class MyD(document.AsyncDocument): class MyD(document.AsyncDocument):
title = field.Text() title = field.Text()
@@ -469,9 +478,9 @@ async def test_you_can_supply_own_mapping_instance():
} == MyD._doc_type.mapping.to_dict() } == MyD._doc_type.mapping.to_dict()
async def test_document_can_be_created_dynamically(): async def test_document_can_be_created_dynamically() -> None:
n = datetime.now() n = datetime.now()
md = MyDoc(title="hello") md: Any = MyDoc(title="hello")
md.name = "My Fancy Document!" md.name = "My Fancy Document!"
md.created_at = n md.created_at = n
@@ -491,13 +500,13 @@ async def test_document_can_be_created_dynamically():
async def test_invalid_date_will_raise_exception() -> None: async def test_invalid_date_will_raise_exception() -> None:
md = MyDoc() md: Any = MyDoc()
md.created_at = "not-a-date" md.created_at = "not-a-date"
with raises(ValidationException): with raises(ValidationException):
md.full_clean() md.full_clean()
async def test_document_inheritance(): async def test_document_inheritance() -> None:
assert issubclass(MySubDoc, MyDoc) assert issubclass(MySubDoc, MyDoc)
assert issubclass(MySubDoc, document.AsyncDocument) assert issubclass(MySubDoc, document.AsyncDocument)
assert hasattr(MySubDoc, "_doc_type") assert hasattr(MySubDoc, "_doc_type")
@@ -511,7 +520,7 @@ async def test_document_inheritance():
} == MySubDoc._doc_type.mapping.to_dict() } == MySubDoc._doc_type.mapping.to_dict()
async def test_child_class_can_override_parent(): async def test_child_class_can_override_parent() -> None:
class A(document.AsyncDocument): class A(document.AsyncDocument):
o = field.Object(dynamic=False, properties={"a": field.Text()}) o = field.Object(dynamic=False, properties={"a": field.Text()})
@@ -530,7 +539,7 @@ async def test_child_class_can_override_parent():
async def test_meta_fields_are_stored_in_meta_and_ignored_by_to_dict() -> None: async def test_meta_fields_are_stored_in_meta_and_ignored_by_to_dict() -> None:
md = MySubDoc(meta={"id": 42}, name="My First doc!") md: Any = MySubDoc(meta={"id": 42}, name="My First doc!")
md.meta.index = "my-index" md.meta.index = "my-index"
assert md.meta.index == "my-index" assert md.meta.index == "my-index"
@@ -539,7 +548,7 @@ async def test_meta_fields_are_stored_in_meta_and_ignored_by_to_dict() -> None:
assert {"id": 42, "index": "my-index"} == md.meta.to_dict() assert {"id": 42, "index": "my-index"} == md.meta.to_dict()
async def test_index_inheritance(): async def test_index_inheritance() -> None:
assert issubclass(MyMultiSubDoc, MySubDoc) assert issubclass(MyMultiSubDoc, MySubDoc)
assert issubclass(MyMultiSubDoc, MyDoc2) assert issubclass(MyMultiSubDoc, MyDoc2)
assert issubclass(MyMultiSubDoc, document.AsyncDocument) assert issubclass(MyMultiSubDoc, document.AsyncDocument)
@@ -558,31 +567,31 @@ async def test_index_inheritance():
async def test_meta_fields_can_be_set_directly_in_init() -> None: async def test_meta_fields_can_be_set_directly_in_init() -> None:
p = object() p = object()
md = MyDoc(_id=p, title="Hello World!") md: Any = MyDoc(_id=p, title="Hello World!")
assert md.meta.id is p assert md.meta.id is p
async def test_save_no_index(mock_client) -> None: async def test_save_no_index(mock_client: Any) -> None:
md = MyDoc() md: Any = MyDoc()
with raises(ValidationException): with raises(ValidationException):
await md.save(using="mock") await md.save(using="mock")
async def test_delete_no_index(mock_client) -> None: async def test_delete_no_index(mock_client: Any) -> None:
md = MyDoc() md: Any = MyDoc()
with raises(ValidationException): with raises(ValidationException):
await md.delete(using="mock") await md.delete(using="mock")
async def test_update_no_fields() -> None: async def test_update_no_fields() -> None:
md = MyDoc() md: Any = MyDoc()
with raises(IllegalOperation): with raises(IllegalOperation):
await md.update() await md.update()
async def test_search_with_custom_alias_and_index(mock_client) -> None: async def test_search_with_custom_alias_and_index(mock_client: Any) -> None:
search_object = MyDoc.search( search_object: Any = MyDoc.search(
using="staging", index=["custom_index1", "custom_index2"] using="staging", index=["custom_index1", "custom_index2"]
) )
@@ -590,8 +599,8 @@ async def test_search_with_custom_alias_and_index(mock_client) -> None:
assert search_object._index == ["custom_index1", "custom_index2"] assert search_object._index == ["custom_index1", "custom_index2"]
async def test_from_opensearch_respects_underscored_non_meta_fields(): async def test_from_opensearch_respects_underscored_non_meta_fields() -> None:
doc = { doc: Any = {
"_index": "test-index", "_index": "test-index",
"_id": "opensearch", "_id": "opensearch",
"_score": 12.0, "_score": 12.0,
@@ -614,11 +623,11 @@ async def test_from_opensearch_respects_underscored_non_meta_fields():
assert c._tagline == "You know, for search" assert c._tagline == "You know, for search"
async def test_nested_and_object_inner_doc(): async def test_nested_and_object_inner_doc() -> None:
class MySubDocWithNested(MyDoc): class MySubDocWithNested(MyDoc):
nested_inner = field.Nested(MyInner) nested_inner = field.Nested(MyInner)
props = MySubDocWithNested._doc_type.mapping.to_dict()["properties"] props: Any = MySubDocWithNested._doc_type.mapping.to_dict()["properties"]
assert props == { assert props == {
"created_at": {"type": "date"}, "created_at": {"type": "date"},
"inner": {"properties": {"old_field": {"type": "text"}}, "type": "object"}, "inner": {"properties": {"old_field": {"type": "text"}}, "type": "object"},
@@ -9,6 +9,7 @@
# GitHub history for details. # GitHub history for details.
from datetime import datetime from datetime import datetime
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -55,7 +56,7 @@ async def test_query_is_created_properly() -> None:
} == s.to_dict() } == s.to_dict()
async def test_query_is_created_properly_with_sort_tuple(): async def test_query_is_created_properly_with_sort_tuple() -> None:
bs = BlogSearch("python search", sort=("category", "-title")) bs = BlogSearch("python search", sort=("category", "-title"))
s = bs.build_search() s = bs.build_search()
@@ -79,7 +80,7 @@ async def test_query_is_created_properly_with_sort_tuple():
} == s.to_dict() } == s.to_dict()
async def test_filter_is_applied_to_search_but_not_relevant_facet(): async def test_filter_is_applied_to_search_but_not_relevant_facet() -> None:
bs = BlogSearch("python search", filters={"category": "opensearch"}) bs = BlogSearch("python search", filters={"category": "opensearch"})
s = bs.build_search() s = bs.build_search()
@@ -102,7 +103,7 @@ async def test_filter_is_applied_to_search_but_not_relevant_facet():
} == s.to_dict() } == s.to_dict()
async def test_filters_are_applied_to_search_ant_relevant_facets(): async def test_filters_are_applied_to_search_ant_relevant_facets() -> None:
bs = BlogSearch( bs = BlogSearch(
"python search", "python search",
filters={"category": "opensearch", "tags": ["python", "django"]}, filters={"category": "opensearch", "tags": ["python", "django"]},
@@ -142,7 +143,7 @@ async def test_date_histogram_facet_with_1970_01_01_date() -> None:
assert dhf.get_value({"key": 0}) == datetime(1970, 1, 1, 0, 0) assert dhf.get_value({"key": 0}) == datetime(1970, 1, 1, 0, 0)
@pytest.mark.parametrize( @pytest.mark.parametrize( # type: ignore
["interval_type", "interval"], ["interval_type", "interval"],
[ [
("interval", "year"), ("interval", "year"),
@@ -169,7 +170,7 @@ async def test_date_histogram_facet_with_1970_01_01_date() -> None:
("fixed_interval", "1h"), ("fixed_interval", "1h"),
], ],
) )
async def test_date_histogram_interval_types(interval_type, interval) -> None: async def test_date_histogram_interval_types(interval_type: Any, interval: Any) -> None:
dhf = DateHistogramFacet(field="@timestamp", **{interval_type: interval}) dhf = DateHistogramFacet(field="@timestamp", **{interval_type: interval})
assert dhf.get_aggregation().to_dict() == { assert dhf.get_aggregation().to_dict() == {
"date_histogram": { "date_histogram": {
@@ -10,6 +10,7 @@
import string import string
from random import choice from random import choice
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -118,7 +119,7 @@ async def test_registered_doc_type_included_in_search() -> None:
async def test_aliases_add_to_object() -> None: async def test_aliases_add_to_object() -> None:
random_alias = "".join((choice(string.ascii_letters) for _ in range(100))) random_alias = "".join((choice(string.ascii_letters) for _ in range(100)))
alias_dict = {random_alias: {}} alias_dict: Any = {random_alias: {}}
index = AsyncIndex("i", using="alias") index = AsyncIndex("i", using="alias")
index.aliases(**alias_dict) index.aliases(**alias_dict)
@@ -128,7 +129,7 @@ async def test_aliases_add_to_object() -> None:
async def test_aliases_returned_from_to_dict() -> None: async def test_aliases_returned_from_to_dict() -> None:
random_alias = "".join((choice(string.ascii_letters) for _ in range(100))) random_alias = "".join((choice(string.ascii_letters) for _ in range(100)))
alias_dict = {random_alias: {}} alias_dict: Any = {random_alias: {}}
index = AsyncIndex("i", using="alias") index = AsyncIndex("i", using="alias")
index.aliases(**alias_dict) index.aliases(**alias_dict)
@@ -136,7 +137,7 @@ async def test_aliases_returned_from_to_dict() -> None:
assert index._aliases == index.to_dict()["aliases"] == alias_dict assert index._aliases == index.to_dict()["aliases"] == alias_dict
async def test_analyzers_added_to_object(): async def test_analyzers_added_to_object() -> None:
random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100))) random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100)))
random_analyzer = analyzer( random_analyzer = analyzer(
random_analyzer_name, tokenizer="standard", filter="standard" random_analyzer_name, tokenizer="standard", filter="standard"
@@ -152,7 +153,7 @@ async def test_analyzers_added_to_object():
} }
async def test_analyzers_returned_from_to_dict(): async def test_analyzers_returned_from_to_dict() -> None:
random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100))) random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100)))
random_analyzer = analyzer( random_analyzer = analyzer(
random_analyzer_name, tokenizer="standard", filter="standard" random_analyzer_name, tokenizer="standard", filter="standard"
@@ -173,7 +174,7 @@ async def test_conflicting_analyzer_raises_error() -> None:
i.analyzer("my_analyzer", tokenizer="keyword", filter=["lowercase", "stop"]) i.analyzer("my_analyzer", tokenizer="keyword", filter=["lowercase", "stop"])
async def test_index_template_can_have_order(): async def test_index_template_can_have_order() -> None:
i = AsyncIndex("i-*") i = AsyncIndex("i-*")
it = i.as_template("i", order=2) it = i.as_template("i", order=2)
@@ -24,7 +24,7 @@ async def test_mapping_can_has_fields() -> None:
} == m.to_dict() } == m.to_dict()
async def test_mapping_update_is_recursive(): async def test_mapping_update_is_recursive() -> None:
m1 = mapping.AsyncMapping() m1 = mapping.AsyncMapping()
m1.field("title", "text") m1.field("title", "text")
m1.field("author", "object") m1.field("author", "object")
@@ -67,7 +67,7 @@ async def test_properties_can_iterate_over_all_the_fields() -> None:
} }
async def test_mapping_can_collect_all_analyzers_and_normalizers(): async def test_mapping_can_collect_all_analyzers_and_normalizers() -> None:
a1 = analysis.analyzer( a1 = analysis.analyzer(
"my_analyzer1", "my_analyzer1",
tokenizer="keyword", tokenizer="keyword",
@@ -140,7 +140,7 @@ async def test_mapping_can_collect_all_analyzers_and_normalizers():
assert json.loads(json.dumps(m.to_dict())) == m.to_dict() assert json.loads(json.dumps(m.to_dict())) == m.to_dict()
async def test_mapping_can_collect_multiple_analyzers(): async def test_mapping_can_collect_multiple_analyzers() -> None:
a1 = analysis.analyzer( a1 = analysis.analyzer(
"my_analyzer1", "my_analyzer1",
tokenizer="keyword", tokenizer="keyword",
@@ -9,6 +9,7 @@
# GitHub history for details. # GitHub history for details.
from copy import deepcopy from copy import deepcopy
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -71,7 +72,7 @@ async def test_query_can_be_assigned_to() -> None:
assert s.query._proxied is q assert s.query._proxied is q
async def test_query_can_be_wrapped(): async def test_query_can_be_wrapped() -> None:
s = search.AsyncSearch().query("match", title="python") s = search.AsyncSearch().query("match", title="python")
s.query = Q("function_score", query=s.query, field_value_factor={"field": "rating"}) s.query = Q("function_score", query=s.query, field_value_factor={"field": "rating"})
@@ -142,7 +143,7 @@ async def test_aggs_allow_two_metric() -> None:
} }
async def test_aggs_get_copied_on_change(): async def test_aggs_get_copied_on_change() -> None:
s = search.AsyncSearch().query("match_all") s = search.AsyncSearch().query("match_all")
s.aggs.bucket("per_tag", "terms", field="f").metric( s.aggs.bucket("per_tag", "terms", field="f").metric(
"max_score", "max", field="score" "max_score", "max", field="score"
@@ -155,7 +156,7 @@ async def test_aggs_get_copied_on_change():
s4 = s3._clone() s4 = s3._clone()
s4.aggs.metric("max_score", "max", field="score") s4.aggs.metric("max_score", "max", field="score")
d = { d: Any = {
"query": {"match_all": {}}, "query": {"match_all": {}},
"aggs": { "aggs": {
"per_tag": { "per_tag": {
@@ -218,7 +219,7 @@ async def test_doc_type_document_class() -> None:
assert s._doc_type_map == {} assert s._doc_type_map == {}
async def test_sort(): async def test_sort() -> None:
s = search.AsyncSearch() s = search.AsyncSearch()
s = s.sort("fielda", "-fieldb") s = s.sort("fielda", "-fieldb")
@@ -254,7 +255,7 @@ async def test_index() -> None:
assert {"from": 3, "size": 1} == s[3].to_dict() assert {"from": 3, "size": 1} == s[3].to_dict()
async def test_search_to_dict(): async def test_search_to_dict() -> None:
s = search.AsyncSearch() s = search.AsyncSearch()
assert {} == s.to_dict() assert {} == s.to_dict()
@@ -283,7 +284,7 @@ async def test_search_to_dict():
assert {"size": 5, "from": 42} == s.to_dict() assert {"size": 5, "from": 42} == s.to_dict()
async def test_complex_example(): async def test_complex_example() -> None:
s = search.AsyncSearch() s = search.AsyncSearch()
s = ( s = (
s.query("match", title="python") s.query("match", title="python")
@@ -334,7 +335,7 @@ async def test_complex_example():
} == s.to_dict() } == s.to_dict()
async def test_reverse(): async def test_reverse() -> None:
d = { d = {
"query": { "query": {
"filtered": { "filtered": {
@@ -406,7 +407,7 @@ async def test_source() -> None:
).source(["f1", "f2"]).to_dict() ).source(["f1", "f2"]).to_dict()
async def test_source_on_clone(): async def test_source_on_clone() -> None:
assert { assert {
"_source": {"includes": ["foo.bar.*"], "excludes": ["foo.one"]}, "_source": {"includes": ["foo.bar.*"], "excludes": ["foo.one"]},
"query": {"bool": {"filter": [{"term": {"title": "python"}}]}}, "query": {"bool": {"filter": [{"term": {"title": "python"}}]}},
@@ -431,7 +432,7 @@ async def test_source_on_clear() -> None:
) )
async def test_suggest_accepts_global_text(): async def test_suggest_accepts_global_text() -> None:
s = search.AsyncSearch.from_dict( s = search.AsyncSearch.from_dict(
{ {
"suggest": { "suggest": {
@@ -453,7 +454,7 @@ async def test_suggest_accepts_global_text():
} == s.to_dict() } == s.to_dict()
async def test_suggest(): async def test_suggest() -> None:
s = search.AsyncSearch() s = search.AsyncSearch()
s = s.suggest("my_suggestion", "pyhton", term={"field": "title"}) s = s.suggest("my_suggestion", "pyhton", term={"field": "title"})
@@ -475,7 +476,7 @@ async def test_exclude() -> None:
} == s.to_dict() } == s.to_dict()
async def test_update_from_dict(): async def test_update_from_dict() -> None:
s = search.AsyncSearch() s = search.AsyncSearch()
s.update_from_dict({"indices_boost": [{"important-documents": 2}]}) s.update_from_dict({"indices_boost": [{"important-documents": 2}]})
s.update_from_dict({"_source": ["id", "name"]}) s.update_from_dict({"_source": ["id", "name"]})
@@ -486,7 +487,7 @@ async def test_update_from_dict():
} == s.to_dict() } == s.to_dict()
async def test_rescore_query_to_dict(): async def test_rescore_query_to_dict() -> None:
s = search.AsyncSearch(index="index-name") s = search.AsyncSearch(index="index-name")
positive_query = Q( positive_query = Q(
@@ -26,7 +26,7 @@ async def test_ubq_starts_with_no_query() -> None:
assert ubq.query._proxied is None assert ubq.query._proxied is None
async def test_ubq_to_dict(): async def test_ubq_to_dict() -> None:
ubq = update_by_query.AsyncUpdateByQuery() ubq = update_by_query.AsyncUpdateByQuery()
assert {} == ubq.to_dict() assert {} == ubq.to_dict()
@@ -44,7 +44,7 @@ async def test_ubq_to_dict():
assert {"extra_q": {"term": {"category": "conference"}}} == ubq.to_dict() assert {"extra_q": {"term": {"category": "conference"}}} == ubq.to_dict()
async def test_complex_example(): async def test_complex_example() -> None:
ubq = update_by_query.AsyncUpdateByQuery() ubq = update_by_query.AsyncUpdateByQuery()
ubq = ( ubq = (
ubq.query("match", title="python") ubq.query("match", title="python")
@@ -95,7 +95,7 @@ async def test_exclude() -> None:
} == ubq.to_dict() } == ubq.to_dict()
async def test_reverse(): async def test_reverse() -> None:
d = { d = {
"query": { "query": {
"filtered": { "filtered": {
@@ -137,7 +137,7 @@ async def test_from_dict_doesnt_need_query() -> None:
assert {"script": {"source": "test"}} == ubq.to_dict() assert {"script": {"source": "test"}} == ubq.to_dict()
async def test_overwrite_script(): async def test_overwrite_script() -> None:
ubq = update_by_query.AsyncUpdateByQuery() ubq = update_by_query.AsyncUpdateByQuery()
ubq = ubq.script( ubq = ubq.script(
source="ctx._source.likes += params.f", lang="painless", params={"f": 3} source="ctx._source.likes += params.f", lang="painless", params={"f": 3}
@@ -26,12 +26,14 @@
# under the License. # under the License.
from typing import Any
import mock import mock
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
from multidict import CIMultiDict from multidict import CIMultiDict
from opensearchpy._async._extra_imports import aiohttp from opensearchpy._async._extra_imports import aiohttp # type: ignore
from opensearchpy._async.compat import get_running_loop from opensearchpy._async.compat import get_running_loop
from opensearchpy.connection.http_async import AsyncHttpConnection from opensearchpy.connection.http_async import AsyncHttpConnection
@@ -52,15 +54,15 @@ class TestAsyncHttpConnection:
assert c._http_auth.password, "password" assert c._http_auth.password, "password"
def test_auth_as_callable(self) -> None: def test_auth_as_callable(self) -> None:
def auth_fn(): def auth_fn() -> None:
pass pass
c = AsyncHttpConnection(http_auth=auth_fn) c = AsyncHttpConnection(http_auth=auth_fn)
assert callable(c._http_auth) assert callable(c._http_auth)
@mock.patch("aiohttp.ClientSession.request", new_callable=mock.Mock) @mock.patch("aiohttp.ClientSession.request", new_callable=mock.Mock)
async def test_basicauth_in_request_session(self, mock_request) -> None: async def test_basicauth_in_request_session(self, mock_request: Any) -> None:
async def do_request(*args, **kwargs): async def do_request(*args: Any, **kwargs: Any) -> Any:
response_mock = mock.AsyncMock() response_mock = mock.AsyncMock()
response_mock.headers = CIMultiDict() response_mock.headers = CIMultiDict()
response_mock.status = 200 response_mock.status = 200
@@ -90,13 +92,13 @@ class TestAsyncHttpConnection:
) )
@mock.patch("aiohttp.ClientSession.request", new_callable=mock.Mock) @mock.patch("aiohttp.ClientSession.request", new_callable=mock.Mock)
async def test_callable_in_request_session(self, mock_request) -> None: async def test_callable_in_request_session(self, mock_request: Any) -> None:
def auth_fn(*args, **kwargs): def auth_fn(*args: Any, **kwargs: Any) -> Any:
return { return {
"Test": "PASSED", "Test": "PASSED",
} }
async def do_request(*args, **kwargs): async def do_request(*args: Any, **kwargs: Any) -> Any:
response_mock = mock.AsyncMock() response_mock = mock.AsyncMock()
response_mock.headers = CIMultiDict() response_mock.headers = CIMultiDict()
response_mock.status = 200 response_mock.status = 200
@@ -17,7 +17,8 @@ class TestPluginsClient(TestCase):
async def test_plugins_client(self) -> None: async def test_plugins_client(self) -> None:
with self.assertWarns(Warning) as w: with self.assertWarns(Warning) as w:
client = AsyncOpenSearch() client = AsyncOpenSearch()
client.plugins.__init__(client) # double-init # testing double-init here
client.plugins.__init__(client) # type: ignore
self.assertEqual( self.assertEqual(
str(w.warnings[0].message), str(w.warnings[0].message),
"Cannot load `alerting` directly to AsyncOpenSearch as it already exists. Use `AsyncOpenSearch.plugin.alerting` instead.", "Cannot load `alerting` directly to AsyncOpenSearch as it already exists. Use `AsyncOpenSearch.plugin.alerting` instead.",
@@ -26,7 +26,7 @@
# under the License. # under the License.
from unittest import IsolatedAsyncioTestCase from unittest import IsolatedAsyncioTestCase # type: ignore
from opensearchpy._async.helpers.test import get_test_client from opensearchpy._async.helpers.test import get_test_client
from opensearchpy.connection.async_connections import add_connection from opensearchpy.connection.async_connections import add_connection
@@ -34,7 +34,7 @@ from opensearchpy.connection.async_connections import add_connection
from ...utils import wipe_cluster from ...utils import wipe_cluster
class AsyncOpenSearchTestCase(IsolatedAsyncioTestCase): class AsyncOpenSearchTestCase(IsolatedAsyncioTestCase): # type: ignore
async def asyncSetUp(self) -> None: async def asyncSetUp(self) -> None:
self.client = await get_test_client( self.client = await get_test_client(
verify_certs=False, http_auth=("admin", "admin") verify_certs=False, http_auth=("admin", "admin")
@@ -27,6 +27,7 @@
import asyncio import asyncio
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -39,15 +40,15 @@ from ...utils import wipe_cluster
pytestmark: MarkDecorator = pytest.mark.asyncio pytestmark: MarkDecorator = pytest.mark.asyncio
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
async def async_client(): async def async_client() -> Any:
client = None client = None
try: try:
if not hasattr(opensearchpy, "AsyncOpenSearch"): if not hasattr(opensearchpy, "AsyncOpenSearch"):
pytest.skip("test requires 'AsyncOpenSearch'") pytest.skip("test requires 'AsyncOpenSearch'")
kw = {"timeout": 3} kw = {"timeout": 3}
client = opensearchpy.AsyncOpenSearch(OPENSEARCH_URL, **kw) client = opensearchpy.AsyncOpenSearch(OPENSEARCH_URL, **kw) # type: ignore
# wait for yellow status # wait for yellow status
for _ in range(100): for _ in range(100):
@@ -28,6 +28,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -35,19 +37,19 @@ pytestmark: MarkDecorator = pytest.mark.asyncio
class TestUnicode: class TestUnicode:
async def test_indices_analyze(self, async_client) -> None: async def test_indices_analyze(self, async_client: Any) -> None:
await async_client.indices.analyze(body='{"text": "привет"}') await async_client.indices.analyze(body='{"text": "привет"}')
class TestBulk: class TestBulk:
async def test_bulk_works_with_string_body(self, async_client) -> None: async def test_bulk_works_with_string_body(self, async_client: Any) -> None:
docs = '{ "index" : { "_index" : "bulk_test_index", "_id" : "1" } }\n{"answer": 42}' docs = '{ "index" : { "_index" : "bulk_test_index", "_id" : "1" } }\n{"answer": 42}'
response = await async_client.bulk(body=docs) response = await async_client.bulk(body=docs)
assert response["errors"] is False assert response["errors"] is False
assert len(response["items"]) == 1 assert len(response["items"]) == 1
async def test_bulk_works_with_bytestring_body(self, async_client) -> None: async def test_bulk_works_with_bytestring_body(self, async_client: Any) -> None:
docs = b'{ "index" : { "_index" : "bulk_test_index", "_id" : "2" } }\n{"answer": 42}' docs = b'{ "index" : { "_index" : "bulk_test_index", "_id" : "2" } }\n{"answer": 42}'
response = await async_client.bulk(body=docs) response = await async_client.bulk(body=docs)
@@ -57,7 +59,7 @@ class TestBulk:
class TestYarlMissing: class TestYarlMissing:
async def test_aiohttp_connection_works_without_yarl( async def test_aiohttp_connection_works_without_yarl(
self, async_client, monkeypatch self, async_client: Any, monkeypatch: Any
) -> None: ) -> None:
# This is a defensive test case for if aiohttp suddenly stops using yarl. # This is a defensive test case for if aiohttp suddenly stops using yarl.
from opensearchpy._async import http_aiohttp from opensearchpy._async import http_aiohttp
@@ -10,6 +10,7 @@
import re import re
from datetime import datetime from datetime import datetime
from typing import Any
import pytest import pytest
from pytest import fixture from pytest import fixture
@@ -34,32 +35,32 @@ from test_opensearchpy.test_async.test_server.test_helpers.test_document import
pytestmark = pytest.mark.asyncio pytestmark = pytest.mark.asyncio
@fixture(scope="function") @fixture(scope="function") # type: ignore
async def client(): async def client() -> Any:
client = await get_test_client(verify_certs=False, http_auth=("admin", "admin")) client = await get_test_client(verify_certs=False, http_auth=("admin", "admin"))
await add_connection("default", client) await add_connection("default", client)
return client return client
@fixture(scope="function") @fixture(scope="function") # type: ignore
async def opensearch_version(client): async def opensearch_version(client: Any) -> Any:
info = await client.info() info = await client.info()
print(info) print(info)
yield tuple( yield tuple(
int(x) int(x)
for x in re.match(r"^([0-9.]+)", info["version"]["number"]).group(1).split(".") for x in re.match(r"^([0-9.]+)", info["version"]["number"]).group(1).split(".") # type: ignore
) )
@fixture @fixture # type: ignore
async def write_client(client): async def write_client(client: Any) -> Any:
yield client yield client
await client.indices.delete("test-*", ignore=404) await client.indices.delete("test-*", ignore=404)
await client.indices.delete_template("test-template", ignore=404) await client.indices.delete_template("test-template", ignore=404)
@fixture @fixture # type: ignore
async def data_client(client): async def data_client(client: Any) -> Any:
# create mappings # create mappings
await create_git_index(client, "git") await create_git_index(client, "git")
await create_flat_git_index(client, "flat-git") await create_flat_git_index(client, "flat-git")
@@ -71,8 +72,8 @@ async def data_client(client):
await client.indices.delete("flat-git", ignore=404) await client.indices.delete("flat-git", ignore=404)
@fixture @fixture # type: ignore
async def pull_request(write_client): async def pull_request(write_client: Any) -> Any:
await PullRequest.init() await PullRequest.init()
pr = PullRequest( pr = PullRequest(
_id=42, _id=42,
@@ -95,8 +96,8 @@ async def pull_request(write_client):
return pr return pr
@fixture @fixture # type: ignore
async def setup_ubq_tests(client) -> str: async def setup_ubq_tests(client: Any) -> str:
index = "test-git" index = "test-git"
await create_git_index(client, index) await create_git_index(client, index)
await async_bulk(client, TEST_GIT_DATA, raise_on_error=True, refresh=True) await async_bulk(client, TEST_GIT_DATA, raise_on_error=True, refresh=True)
@@ -27,7 +27,7 @@
import asyncio import asyncio
from typing import Tuple from typing import Any, List
import pytest import pytest
from mock import MagicMock, patch from mock import MagicMock, patch
@@ -40,19 +40,19 @@ pytestmark = pytest.mark.asyncio
class AsyncMock(MagicMock): class AsyncMock(MagicMock):
async def __call__(self, *args, **kwargs): async def __call__(self, *args: Any, **kwargs: Any) -> Any:
return super(AsyncMock, self).__call__(*args, **kwargs) return super(AsyncMock, self).__call__(*args, **kwargs)
def __await__(self): def __await__(self) -> Any:
return self().__await__() return self().__await__()
class FailingBulkClient(object): class FailingBulkClient(object):
def __init__( def __init__(
self, self,
client, client: Any,
fail_at: Tuple[int] = (2,), fail_at: Any = (2,),
fail_with=TransportError(599, "Error!", {}), fail_with: TransportError = TransportError(599, "Error!", {}),
) -> None: ) -> None:
self.client = client self.client = client
self._called = 0 self._called = 0
@@ -60,7 +60,7 @@ class FailingBulkClient(object):
self.transport = client.transport self.transport = client.transport
self._fail_with = fail_with self._fail_with = fail_with
async def bulk(self, *args, **kwargs): async def bulk(self, *args: Any, **kwargs: Any) -> Any:
self._called += 1 self._called += 1
if self._called in self._fail_at: if self._called in self._fail_at:
raise self._fail_with raise self._fail_with
@@ -68,7 +68,7 @@ class FailingBulkClient(object):
class TestStreamingBulk(object): class TestStreamingBulk(object):
async def test_actions_remain_unchanged(self, async_client) -> None: async def test_actions_remain_unchanged(self, async_client: Any) -> None:
actions1 = [{"_id": 1}, {"_id": 2}] actions1 = [{"_id": 1}, {"_id": 2}]
async for ok, item in actions.async_streaming_bulk( async for ok, item in actions.async_streaming_bulk(
async_client, actions1, index="test-index" async_client, actions1, index="test-index"
@@ -76,7 +76,7 @@ class TestStreamingBulk(object):
assert ok assert ok
assert [{"_id": 1}, {"_id": 2}] == actions1 assert [{"_id": 1}, {"_id": 2}] == actions1
async def test_all_documents_get_inserted(self, async_client) -> None: async def test_all_documents_get_inserted(self, async_client: Any) -> None:
docs = [{"answer": x, "_id": x} for x in range(100)] docs = [{"answer": x, "_id": x} for x in range(100)]
async for ok, item in actions.async_streaming_bulk( async for ok, item in actions.async_streaming_bulk(
async_client, docs, index="test-index", refresh=True async_client, docs, index="test-index", refresh=True
@@ -88,13 +88,13 @@ class TestStreamingBulk(object):
"_source" "_source"
] ]
async def test_documents_data_types(self, async_client): async def test_documents_data_types(self, async_client: Any) -> None:
async def async_gen(): async def async_gen() -> Any:
for x in range(100): for x in range(100):
await asyncio.sleep(0) await asyncio.sleep(0)
yield {"answer": x, "_id": x} yield {"answer": x, "_id": x}
def sync_gen(): def sync_gen() -> Any:
for x in range(100): for x in range(100):
yield {"answer": x, "_id": x} yield {"answer": x, "_id": x}
@@ -123,7 +123,7 @@ class TestStreamingBulk(object):
] ]
async def test_all_errors_from_chunk_are_raised_on_failure( async def test_all_errors_from_chunk_are_raised_on_failure(
self, async_client self, async_client: Any
) -> None: ) -> None:
await async_client.indices.create( await async_client.indices.create(
"i", "i",
@@ -144,7 +144,7 @@ class TestStreamingBulk(object):
else: else:
assert False, "exception should have been raised" assert False, "exception should have been raised"
async def test_different_op_types(self, async_client): async def test_different_op_types(self, async_client: Any) -> None:
await async_client.index(index="i", id=45, body={}) await async_client.index(index="i", id=45, body={})
await async_client.index(index="i", id=42, body={}) await async_client.index(index="i", id=42, body={})
docs = [ docs = [
@@ -159,7 +159,7 @@ class TestStreamingBulk(object):
assert {"answer": 42} == (await async_client.get(index="i", id=42))["_source"] assert {"answer": 42} == (await async_client.get(index="i", id=42))["_source"]
assert {"f": "v"} == (await async_client.get(index="i", id=47))["_source"] assert {"f": "v"} == (await async_client.get(index="i", id=47))["_source"]
async def test_transport_error_can_becaught(self, async_client): async def test_transport_error_can_becaught(self, async_client: Any) -> None:
failing_client = FailingBulkClient(async_client) failing_client = FailingBulkClient(async_client)
docs = [ docs = [
{"_index": "i", "_id": 47, "f": "v"}, {"_index": "i", "_id": 47, "f": "v"},
@@ -193,7 +193,7 @@ class TestStreamingBulk(object):
} }
} == results[1][1] } == results[1][1]
async def test_rejected_documents_are_retried(self, async_client) -> None: async def test_rejected_documents_are_retried(self, async_client: Any) -> None:
failing_client = FailingBulkClient( failing_client = FailingBulkClient(
async_client, fail_with=TransportError(429, "Rejected!", {}) async_client, fail_with=TransportError(429, "Rejected!", {})
) )
@@ -222,7 +222,7 @@ class TestStreamingBulk(object):
assert 4 == failing_client._called assert 4 == failing_client._called
async def test_rejected_documents_are_retried_at_most_max_retries_times( async def test_rejected_documents_are_retried_at_most_max_retries_times(
self, async_client self, async_client: Any
) -> None: ) -> None:
failing_client = FailingBulkClient( failing_client = FailingBulkClient(
async_client, fail_at=(1, 2), fail_with=TransportError(429, "Rejected!", {}) async_client, fail_at=(1, 2), fail_with=TransportError(429, "Rejected!", {})
@@ -253,7 +253,7 @@ class TestStreamingBulk(object):
assert 4 == failing_client._called assert 4 == failing_client._called
async def test_transport_error_is_raised_with_max_retries( async def test_transport_error_is_raised_with_max_retries(
self, async_client self, async_client: Any
) -> None: ) -> None:
failing_client = FailingBulkClient( failing_client = FailingBulkClient(
async_client, async_client,
@@ -261,7 +261,7 @@ class TestStreamingBulk(object):
fail_with=TransportError(429, "Rejected!", {}), fail_with=TransportError(429, "Rejected!", {}),
) )
async def streaming_bulk(): async def streaming_bulk() -> Any:
results = [ results = [
x x
async for x in actions.async_streaming_bulk( async for x in actions.async_streaming_bulk(
@@ -280,7 +280,7 @@ class TestStreamingBulk(object):
class TestBulk(object): class TestBulk(object):
async def test_bulk_works_with_single_item(self, async_client) -> None: async def test_bulk_works_with_single_item(self, async_client: Any) -> None:
docs = [{"answer": 42, "_id": 1}] docs = [{"answer": 42, "_id": 1}]
success, failed = await actions.async_bulk( success, failed = await actions.async_bulk(
async_client, docs, index="test-index", refresh=True async_client, docs, index="test-index", refresh=True
@@ -293,7 +293,7 @@ class TestBulk(object):
"_source" "_source"
] ]
async def test_all_documents_get_inserted(self, async_client) -> None: async def test_all_documents_get_inserted(self, async_client: Any) -> None:
docs = [{"answer": x, "_id": x} for x in range(100)] docs = [{"answer": x, "_id": x} for x in range(100)]
success, failed = await actions.async_bulk( success, failed = await actions.async_bulk(
async_client, docs, index="test-index", refresh=True async_client, docs, index="test-index", refresh=True
@@ -306,7 +306,7 @@ class TestBulk(object):
"_source" "_source"
] ]
async def test_stats_only_reports_numbers(self, async_client) -> None: async def test_stats_only_reports_numbers(self, async_client: Any) -> None:
docs = [{"answer": x} for x in range(100)] docs = [{"answer": x} for x in range(100)]
success, failed = await actions.async_bulk( success, failed = await actions.async_bulk(
async_client, docs, index="test-index", refresh=True, stats_only=True async_client, docs, index="test-index", refresh=True, stats_only=True
@@ -316,7 +316,7 @@ class TestBulk(object):
assert 0 == failed assert 0 == failed
assert 100 == (await async_client.count(index="test-index"))["count"] assert 100 == (await async_client.count(index="test-index"))["count"]
async def test_errors_are_reported_correctly(self, async_client): async def test_errors_are_reported_correctly(self, async_client: Any) -> None:
await async_client.indices.create( await async_client.indices.create(
"i", "i",
{ {
@@ -333,6 +333,7 @@ class TestBulk(object):
raise_on_error=False, raise_on_error=False,
) )
assert 1 == success assert 1 == success
assert isinstance(failed, List)
assert 1 == len(failed) assert 1 == len(failed)
error = failed[0] error = failed[0]
assert "42" == error["index"]["_id"] assert "42" == error["index"]["_id"]
@@ -342,7 +343,7 @@ class TestBulk(object):
error["index"]["error"] error["index"]["error"]
) or "mapper_parsing_exception" in repr(error["index"]["error"]) ) or "mapper_parsing_exception" in repr(error["index"]["error"])
async def test_error_is_raised(self, async_client): async def test_error_is_raised(self, async_client: Any) -> None:
await async_client.indices.create( await async_client.indices.create(
"i", "i",
{ {
@@ -355,7 +356,7 @@ class TestBulk(object):
with pytest.raises(BulkIndexError): with pytest.raises(BulkIndexError):
await actions.async_bulk(async_client, [{"a": 42}, {"a": "c"}], index="i") await actions.async_bulk(async_client, [{"a": 42}, {"a": "c"}], index="i")
async def test_ignore_error_if_raised(self, async_client): async def test_ignore_error_if_raised(self, async_client: Any) -> None:
# ignore the status code 400 in tuple # ignore the status code 400 in tuple
await actions.async_bulk( await actions.async_bulk(
async_client, [{"a": 42}, {"a": "c"}], index="i", ignore_status=(400,) async_client, [{"a": 42}, {"a": "c"}], index="i", ignore_status=(400,)
@@ -388,7 +389,7 @@ class TestBulk(object):
failing_client, [{"a": 42}], index="i", ignore_status=(599,) failing_client, [{"a": 42}], index="i", ignore_status=(599,)
) )
async def test_errors_are_collected_properly(self, async_client): async def test_errors_are_collected_properly(self, async_client: Any) -> None:
await async_client.indices.create( await async_client.indices.create(
"i", "i",
{ {
@@ -410,10 +411,12 @@ class TestBulk(object):
class MockScroll: class MockScroll:
calls: Any
def __init__(self) -> None: def __init__(self) -> None:
self.calls = [] self.calls = []
async def __call__(self, *args, **kwargs): async def __call__(self, *args: Any, **kwargs: Any) -> Any:
self.calls.append((args, kwargs)) self.calls.append((args, kwargs))
if len(self.calls) == 1: if len(self.calls) == 1:
return { return {
@@ -432,25 +435,27 @@ class MockScroll:
class MockResponse: class MockResponse:
def __init__(self, resp) -> None: def __init__(self, resp: Any) -> None:
self.resp = resp self.resp = resp
async def __call__(self, *args, **kwargs): async def __call__(self, *args: Any, **kwargs: Any) -> Any:
return self.resp return self.resp
def __await__(self): def __await__(self) -> Any:
return self().__await__() return self().__await__()
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
async def scan_teardown(async_client): async def scan_teardown(async_client: Any) -> Any:
yield yield
await async_client.clear_scroll(scroll_id="_all") await async_client.clear_scroll(scroll_id="_all")
class TestScan(object): class TestScan(object):
async def test_order_can_be_preserved(self, async_client, scan_teardown): async def test_order_can_be_preserved(
bulk = [] self, async_client: Any, scan_teardown: Any
) -> None:
bulk: Any = []
for x in range(100): for x in range(100):
bulk.append({"index": {"_index": "test_index", "_id": x}}) bulk.append({"index": {"_index": "test_index", "_id": x}})
bulk.append({"answer": x, "correct": x == 42}) bulk.append({"answer": x, "correct": x == 42})
@@ -470,8 +475,10 @@ class TestScan(object):
assert list(map(str, range(100))) == list(d["_id"] for d in docs) assert list(map(str, range(100))) == list(d["_id"] for d in docs)
assert list(range(100)) == list(d["_source"]["answer"] for d in docs) assert list(range(100)) == list(d["_source"]["answer"] for d in docs)
async def test_all_documents_are_read(self, async_client, scan_teardown): async def test_all_documents_are_read(
bulk = [] self, async_client: Any, scan_teardown: Any
) -> None:
bulk: Any = []
for x in range(100): for x in range(100):
bulk.append({"index": {"_index": "test_index", "_id": x}}) bulk.append({"index": {"_index": "test_index", "_id": x}})
bulk.append({"answer": x, "correct": x == 42}) bulk.append({"answer": x, "correct": x == 42})
@@ -486,8 +493,8 @@ class TestScan(object):
assert set(map(str, range(100))) == set(d["_id"] for d in docs) assert set(map(str, range(100))) == set(d["_id"] for d in docs)
assert set(range(100)) == set(d["_source"]["answer"] for d in docs) assert set(range(100)) == set(d["_source"]["answer"] for d in docs)
async def test_scroll_error(self, async_client, scan_teardown): async def test_scroll_error(self, async_client: Any, scan_teardown: Any) -> None:
bulk = [] bulk: Any = []
for x in range(4): for x in range(4):
bulk.append({"index": {"_index": "test_index"}}) bulk.append({"index": {"_index": "test_index"}})
bulk.append({"value": x}) bulk.append({"value": x})
@@ -522,7 +529,9 @@ class TestScan(object):
assert len(data) == 3 assert len(data) == 3
assert data[-1] == {"scroll_data": 42} assert data[-1] == {"scroll_data": 42}
async def test_initial_search_error(self, async_client, scan_teardown): async def test_initial_search_error(
self, async_client: Any, scan_teardown: Any
) -> None:
with patch.object(async_client, "clear_scroll", new_callable=AsyncMock): with patch.object(async_client, "clear_scroll", new_callable=AsyncMock):
with patch.object( with patch.object(
async_client, async_client,
@@ -572,7 +581,9 @@ class TestScan(object):
assert data == [{"search_data": 1}] assert data == [{"search_data": 1}]
assert mock_scroll.calls == [] assert mock_scroll.calls == []
async def test_no_scroll_id_fast_route(self, async_client, scan_teardown) -> None: async def test_no_scroll_id_fast_route(
self, async_client: Any, scan_teardown: Any
) -> None:
with patch.object(async_client, "search", MockResponse({"no": "_scroll_id"})): with patch.object(async_client, "search", MockResponse({"no": "_scroll_id"})):
with patch.object(async_client, "scroll") as scroll_mock: with patch.object(async_client, "scroll") as scroll_mock:
with patch.object(async_client, "clear_scroll") as clear_mock: with patch.object(async_client, "clear_scroll") as clear_mock:
@@ -588,8 +599,10 @@ class TestScan(object):
clear_mock.assert_not_called() clear_mock.assert_not_called()
@patch("opensearchpy._async.helpers.actions.logger") @patch("opensearchpy._async.helpers.actions.logger")
async def test_logger(self, logger_mock, async_client, scan_teardown): async def test_logger(
bulk = [] self, logger_mock: Any, async_client: Any, scan_teardown: Any
) -> None:
bulk: Any = []
for x in range(4): for x in range(4):
bulk.append({"index": {"_index": "test_index"}}) bulk.append({"index": {"_index": "test_index"}})
bulk.append({"value": x}) bulk.append({"value": x})
@@ -629,8 +642,8 @@ class TestScan(object):
5, 5,
) )
async def test_clear_scroll(self, async_client, scan_teardown): async def test_clear_scroll(self, async_client: Any, scan_teardown: Any) -> None:
bulk = [] bulk: Any = []
for x in range(4): for x in range(4):
bulk.append({"index": {"_index": "test_index"}}) bulk.append({"index": {"_index": "test_index"}})
bulk.append({"value": x}) bulk.append({"value": x})
@@ -665,7 +678,7 @@ class TestScan(object):
] ]
spy.assert_not_called() spy.assert_not_called()
@pytest.mark.parametrize( @pytest.mark.parametrize( # type: ignore
"kwargs", "kwargs",
[ [
{"api_key": ("name", "value")}, {"api_key": ("name", "value")},
@@ -674,8 +687,8 @@ class TestScan(object):
], ],
) )
async def test_scan_auth_kwargs_forwarded( async def test_scan_auth_kwargs_forwarded(
self, async_client, scan_teardown, kwargs self, async_client: Any, scan_teardown: Any, kwargs: Any
): ) -> None:
((key, val),) = kwargs.items() ((key, val),) = kwargs.items()
with patch.object( with patch.object(
@@ -716,8 +729,8 @@ class TestScan(object):
assert api_mock.call_args[1][key] == val assert api_mock.call_args[1][key] == val
async def test_scan_auth_kwargs_favor_scroll_kwargs_option( async def test_scan_auth_kwargs_favor_scroll_kwargs_option(
self, async_client, scan_teardown self, async_client: Any, scan_teardown: Any
): ) -> None:
with patch.object( with patch.object(
async_client, async_client,
"search", "search",
@@ -765,9 +778,9 @@ class TestScan(object):
assert async_client.scroll.call_args[1]["sort"] == "asc" assert async_client.scroll.call_args[1]["sort"] == "asc"
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
async def reindex_setup(async_client): async def reindex_setup(async_client: Any) -> Any:
bulk = [] bulk: Any = []
for x in range(100): for x in range(100):
bulk.append({"index": {"_index": "test_index", "_id": x}}) bulk.append({"index": {"_index": "test_index", "_id": x}})
bulk.append( bulk.append(
@@ -783,7 +796,7 @@ async def reindex_setup(async_client):
class TestReindex(object): class TestReindex(object):
async def test_reindex_passes_kwargs_to_scan_and_bulk( async def test_reindex_passes_kwargs_to_scan_and_bulk(
self, async_client, reindex_setup self, async_client: Any, reindex_setup: Any
) -> None: ) -> None:
await actions.async_reindex( await actions.async_reindex(
async_client, async_client,
@@ -803,7 +816,9 @@ class TestReindex(object):
await async_client.get(index="prod_index", id=42) await async_client.get(index="prod_index", id=42)
)["_source"] )["_source"]
async def test_reindex_accepts_a_query(self, async_client, reindex_setup) -> None: async def test_reindex_accepts_a_query(
self, async_client: Any, reindex_setup: Any
) -> None:
await actions.async_reindex( await actions.async_reindex(
async_client, async_client,
"test_index", "test_index",
@@ -822,7 +837,9 @@ class TestReindex(object):
await async_client.get(index="prod_index", id=42) await async_client.get(index="prod_index", id=42)
)["_source"] )["_source"]
async def test_all_documents_get_moved(self, async_client, reindex_setup) -> None: async def test_all_documents_get_moved(
self, async_client: Any, reindex_setup: Any
) -> None:
await actions.async_reindex(async_client, "test_index", "prod_index") await actions.async_reindex(async_client, "test_index", "prod_index")
await async_client.indices.refresh() await async_client.indices.refresh()
@@ -843,8 +860,8 @@ class TestReindex(object):
)["_source"] )["_source"]
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
async def parent_reindex_setup(async_client): async def parent_reindex_setup(async_client: Any) -> None:
body = { body = {
"settings": {"number_of_shards": 1, "number_of_replicas": 0}, "settings": {"number_of_shards": 1, "number_of_replicas": 0},
"mappings": { "mappings": {
@@ -873,8 +890,8 @@ async def parent_reindex_setup(async_client):
class TestParentChildReindex: class TestParentChildReindex:
async def test_children_are_reindexed_correctly( async def test_children_are_reindexed_correctly(
self, async_client, parent_reindex_setup self, async_client: Any, parent_reindex_setup: Any
): ) -> None:
await actions.async_reindex(async_client, "test-index", "real-index") await actions.async_reindex(async_client, "test-index", "real-index")
assert {"question_answer": "question"} == ( assert {"question_answer": "question"} == (
await async_client.get(index="real-index", id=42) await async_client.get(index="real-index", id=42)
@@ -13,7 +13,7 @@ from __future__ import unicode_literals
from typing import Any, Dict from typing import Any, Dict
async def create_flat_git_index(client, index): async def create_flat_git_index(client: Any, index: Any) -> None:
# we will use user on several places # we will use user on several places
user_mapping = { user_mapping = {
"properties": {"name": {"type": "text", "fields": {"raw": {"type": "keyword"}}}} "properties": {"name": {"type": "text", "fields": {"raw": {"type": "keyword"}}}}
@@ -56,7 +56,7 @@ async def create_flat_git_index(client, index):
) )
async def create_git_index(client, index): async def create_git_index(client: Any, index: Any) -> None:
# we will use user on several places # we will use user on several places
user_mapping = { user_mapping = {
"properties": {"name": {"type": "text", "fields": {"raw": {"type": "keyword"}}}} "properties": {"name": {"type": "text", "fields": {"raw": {"type": "keyword"}}}}
@@ -1078,7 +1078,7 @@ DATA = [
] ]
def flatten_doc(d) -> Dict[str, Any]: def flatten_doc(d: Any) -> Dict[str, Any]:
src = d["_source"].copy() src = d["_source"].copy()
del src["commit_repo"] del src["commit_repo"]
return {"_index": "flat-git", "_id": d["_id"], "_source": src} return {"_index": "flat-git", "_id": d["_id"], "_source": src}
@@ -1087,7 +1087,7 @@ def flatten_doc(d) -> Dict[str, Any]:
FLAT_DATA = [flatten_doc(d) for d in DATA if "routing" in d] FLAT_DATA = [flatten_doc(d) for d in DATA if "routing" in d]
def create_test_git_data(d) -> Dict[str, Any]: def create_test_git_data(d: Any) -> Dict[str, Any]:
src = d["_source"].copy() src = d["_source"].copy()
return { return {
"_index": "test-git", "_index": "test-git",
@@ -10,6 +10,7 @@
from datetime import datetime from datetime import datetime
from ipaddress import ip_address from ipaddress import ip_address
from typing import Any, Optional
import pytest import pytest
from pytest import raises from pytest import raises
@@ -63,7 +64,7 @@ class Repository(AsyncDocument):
tags = Keyword() tags = Keyword()
@classmethod @classmethod
def search(cls): def search(cls, using: Any = None, index: Optional[str] = None) -> Any:
return super(Repository, cls).search().filter("term", commit_repo="repo") return super(Repository, cls).search().filter("term", commit_repo="repo")
class Index: class Index:
@@ -116,7 +117,7 @@ class SerializationDoc(AsyncDocument):
name = "test-serialization" name = "test-serialization"
async def test_serialization(write_client): async def test_serialization(write_client: Any) -> None:
await SerializationDoc.init() await SerializationDoc.init()
await write_client.index( await write_client.index(
index="test-serialization", index="test-serialization",
@@ -129,7 +130,7 @@ async def test_serialization(write_client):
"ip": ["::1", "127.0.0.1", None], "ip": ["::1", "127.0.0.1", None],
}, },
) )
sd = await SerializationDoc.get(id=42) sd: Any = await SerializationDoc.get(id=42)
assert sd.i == [1, 2, 3, None] assert sd.i == [1, 2, 3, None]
assert sd.b == [True, False, True, False, None] assert sd.b == [True, False, True, False, None]
@@ -146,7 +147,7 @@ async def test_serialization(write_client):
} }
async def test_nested_inner_hits_are_wrapped_properly(pull_request) -> None: async def test_nested_inner_hits_are_wrapped_properly(pull_request: Any) -> None:
history_query = Q( history_query = Q(
"nested", "nested",
path="comments.history", path="comments.history",
@@ -174,7 +175,7 @@ async def test_nested_inner_hits_are_wrapped_properly(pull_request) -> None:
assert "score" in history.meta assert "score" in history.meta
async def test_nested_inner_hits_are_deserialized_properly(pull_request) -> None: async def test_nested_inner_hits_are_deserialized_properly(pull_request: Any) -> None:
s = PullRequest.search().query( s = PullRequest.search().query(
"nested", "nested",
inner_hits={}, inner_hits={},
@@ -189,7 +190,7 @@ async def test_nested_inner_hits_are_deserialized_properly(pull_request) -> None
assert isinstance(pr.comments[0].created_at, datetime) assert isinstance(pr.comments[0].created_at, datetime)
async def test_nested_top_hits_are_wrapped_properly(pull_request) -> None: async def test_nested_top_hits_are_wrapped_properly(pull_request: Any) -> None:
s = PullRequest.search() s = PullRequest.search()
s.aggs.bucket("comments", "nested", path="comments").metric( s.aggs.bucket("comments", "nested", path="comments").metric(
"hits", "top_hits", size=1 "hits", "top_hits", size=1
@@ -201,7 +202,7 @@ async def test_nested_top_hits_are_wrapped_properly(pull_request) -> None:
assert isinstance(r.aggregations.comments.hits.hits[0], Comment) assert isinstance(r.aggregations.comments.hits.hits[0], Comment)
async def test_update_object_field(write_client) -> None: async def test_update_object_field(write_client: Any) -> None:
await Wiki.init() await Wiki.init()
w = Wiki( w = Wiki(
owner=User(name="Honza Kral"), owner=User(name="Honza Kral"),
@@ -221,7 +222,7 @@ async def test_update_object_field(write_client) -> None:
assert w.ranked == {"test1": 0.1, "topic2": 0.2} assert w.ranked == {"test1": 0.1, "topic2": 0.2}
async def test_update_script(write_client) -> None: async def test_update_script(write_client: Any) -> None:
await Wiki.init() await Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42) w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
await w.save() await w.save()
@@ -231,7 +232,7 @@ async def test_update_script(write_client) -> None:
assert w.views == 47 assert w.views == 47
async def test_update_retry_on_conflict(write_client) -> None: async def test_update_retry_on_conflict(write_client: Any) -> None:
await Wiki.init() await Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42) w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
await w.save() await w.save()
@@ -249,8 +250,10 @@ async def test_update_retry_on_conflict(write_client) -> None:
assert w.views == 52 assert w.views == 52
@pytest.mark.parametrize("retry_on_conflict", [None, 0]) @pytest.mark.parametrize("retry_on_conflict", [None, 0]) # type: ignore
async def test_update_conflicting_version(write_client, retry_on_conflict) -> None: async def test_update_conflicting_version(
write_client: Any, retry_on_conflict: bool
) -> None:
await Wiki.init() await Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42) w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
await w.save() await w.save()
@@ -267,7 +270,7 @@ async def test_update_conflicting_version(write_client, retry_on_conflict) -> No
) )
async def test_save_and_update_return_doc_meta(write_client) -> None: async def test_save_and_update_return_doc_meta(write_client: Any) -> None:
await Wiki.init() await Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42) w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
resp = await w.save(return_doc_meta=True) resp = await w.save(return_doc_meta=True)
@@ -291,33 +294,33 @@ async def test_save_and_update_return_doc_meta(write_client) -> None:
assert resp.keys().__contains__("_version") assert resp.keys().__contains__("_version")
async def test_init(write_client) -> None: async def test_init(write_client: Any) -> None:
await Repository.init(index="test-git") await Repository.init(index="test-git")
assert await write_client.indices.exists(index="test-git") assert await write_client.indices.exists(index="test-git")
async def test_get_raises_404_on_index_missing(data_client) -> None: async def test_get_raises_404_on_index_missing(data_client: Any) -> None:
with raises(NotFoundError): with raises(NotFoundError):
await Repository.get("opensearch-dsl-php", index="not-there") await Repository.get("opensearch-dsl-php", index="not-there")
async def test_get_raises_404_on_non_existent_id(data_client) -> None: async def test_get_raises_404_on_non_existent_id(data_client: Any) -> None:
with raises(NotFoundError): with raises(NotFoundError):
await Repository.get("opensearch-dsl-php") await Repository.get("opensearch-dsl-php")
async def test_get_returns_none_if_404_ignored(data_client) -> None: async def test_get_returns_none_if_404_ignored(data_client: Any) -> None:
assert None is await Repository.get("opensearch-dsl-php", ignore=404) assert None is await Repository.get("opensearch-dsl-php", ignore=404)
async def test_get_returns_none_if_404_ignored_and_index_doesnt_exist( async def test_get_returns_none_if_404_ignored_and_index_doesnt_exist(
data_client, data_client: Any,
) -> None: ) -> None:
assert None is await Repository.get("42", index="not-there", ignore=404) assert None is await Repository.get("42", index="not-there", ignore=404)
async def test_get(data_client) -> None: async def test_get(data_client: Any) -> None:
opensearch_repo = await Repository.get("opensearch-py") opensearch_repo = await Repository.get("opensearch-py")
assert isinstance(opensearch_repo, Repository) assert isinstance(opensearch_repo, Repository)
@@ -325,15 +328,15 @@ async def test_get(data_client) -> None:
assert datetime(2014, 3, 3) == opensearch_repo.created_at assert datetime(2014, 3, 3) == opensearch_repo.created_at
async def test_exists_return_true(data_client) -> None: async def test_exists_return_true(data_client: Any) -> None:
assert await Repository.exists("opensearch-py") assert await Repository.exists("opensearch-py")
async def test_exists_false(data_client) -> None: async def test_exists_false(data_client: Any) -> None:
assert not await Repository.exists("opensearch-dsl-php") assert not await Repository.exists("opensearch-dsl-php")
async def test_get_with_tz_date(data_client) -> None: async def test_get_with_tz_date(data_client: Any) -> None:
first_commit = await Commit.get( first_commit = await Commit.get(
id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py" id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py"
) )
@@ -345,7 +348,7 @@ async def test_get_with_tz_date(data_client) -> None:
) )
async def test_save_with_tz_date(data_client) -> None: async def test_save_with_tz_date(data_client: Any) -> None:
tzinfo = timezone("Europe/Prague") tzinfo = timezone("Europe/Prague")
first_commit = await Commit.get( first_commit = await Commit.get(
id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py" id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py"
@@ -372,7 +375,7 @@ COMMIT_DOCS_WITH_MISSING = [
] ]
async def test_mget(data_client) -> None: async def test_mget(data_client: Any) -> None:
commits = await Commit.mget(COMMIT_DOCS_WITH_MISSING) commits = await Commit.mget(COMMIT_DOCS_WITH_MISSING)
assert commits[0] is None assert commits[0] is None
assert commits[1].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037" assert commits[1].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037"
@@ -380,25 +383,27 @@ async def test_mget(data_client) -> None:
assert commits[3].meta.id == "eb3e543323f189fd7b698e66295427204fff5755" assert commits[3].meta.id == "eb3e543323f189fd7b698e66295427204fff5755"
async def test_mget_raises_exception_when_missing_param_is_invalid(data_client) -> None: async def test_mget_raises_exception_when_missing_param_is_invalid(
data_client: Any,
) -> None:
with raises(ValueError): with raises(ValueError):
await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raj") await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raj")
async def test_mget_raises_404_when_missing_param_is_raise(data_client) -> None: async def test_mget_raises_404_when_missing_param_is_raise(data_client: Any) -> None:
with raises(NotFoundError): with raises(NotFoundError):
await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raise") await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raise")
async def test_mget_ignores_missing_docs_when_missing_param_is_skip( async def test_mget_ignores_missing_docs_when_missing_param_is_skip(
data_client, data_client: Any,
) -> None: ) -> None:
commits = await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="skip") commits = await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="skip")
assert commits[0].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037" assert commits[0].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037"
assert commits[1].meta.id == "eb3e543323f189fd7b698e66295427204fff5755" assert commits[1].meta.id == "eb3e543323f189fd7b698e66295427204fff5755"
async def test_update_works_from_search_response(data_client) -> None: async def test_update_works_from_search_response(data_client: Any) -> None:
opensearch_repo = (await Repository.search().execute())[0] opensearch_repo = (await Repository.search().execute())[0]
await opensearch_repo.update(owner={"other_name": "opensearchpy"}) await opensearch_repo.update(owner={"other_name": "opensearchpy"})
@@ -409,7 +414,7 @@ async def test_update_works_from_search_response(data_client) -> None:
assert "opensearch" == new_version.owner.name assert "opensearch" == new_version.owner.name
async def test_update(data_client) -> None: async def test_update(data_client: Any) -> None:
opensearch_repo = await Repository.get("opensearch-py") opensearch_repo = await Repository.get("opensearch-py")
v = opensearch_repo.meta.version v = opensearch_repo.meta.version
@@ -433,7 +438,7 @@ async def test_update(data_client) -> None:
assert "primary_term" in new_version.meta assert "primary_term" in new_version.meta
async def test_save_updates_existing_doc(data_client) -> None: async def test_save_updates_existing_doc(data_client: Any) -> None:
opensearch_repo = await Repository.get("opensearch-py") opensearch_repo = await Repository.get("opensearch-py")
opensearch_repo.new_field = "testing-save" opensearch_repo.new_field = "testing-save"
@@ -446,7 +451,9 @@ async def test_save_updates_existing_doc(data_client) -> None:
assert new_repo["_seq_no"] == opensearch_repo.meta.seq_no assert new_repo["_seq_no"] == opensearch_repo.meta.seq_no
async def test_save_automatically_uses_seq_no_and_primary_term(data_client) -> None: async def test_save_automatically_uses_seq_no_and_primary_term(
data_client: Any,
) -> None:
opensearch_repo = await Repository.get("opensearch-py") opensearch_repo = await Repository.get("opensearch-py")
opensearch_repo.meta.seq_no += 1 opensearch_repo.meta.seq_no += 1
@@ -454,7 +461,9 @@ async def test_save_automatically_uses_seq_no_and_primary_term(data_client) -> N
await opensearch_repo.save() await opensearch_repo.save()
async def test_delete_automatically_uses_seq_no_and_primary_term(data_client) -> None: async def test_delete_automatically_uses_seq_no_and_primary_term(
data_client: Any,
) -> None:
opensearch_repo = await Repository.get("opensearch-py") opensearch_repo = await Repository.get("opensearch-py")
opensearch_repo.meta.seq_no += 1 opensearch_repo.meta.seq_no += 1
@@ -462,13 +471,13 @@ async def test_delete_automatically_uses_seq_no_and_primary_term(data_client) ->
await opensearch_repo.delete() await opensearch_repo.delete()
async def assert_doc_equals(expected, actual) -> None: async def assert_doc_equals(expected: Any, actual: Any) -> None:
async for f in aiter(expected): async for f in aiter(expected):
assert f in actual assert f in actual
assert actual[f] == expected[f] assert actual[f] == expected[f]
async def test_can_save_to_different_index(write_client): async def test_can_save_to_different_index(write_client: Any) -> None:
test_repo = Repository(description="testing", meta={"id": 42}) test_repo = Repository(description="testing", meta={"id": 42})
assert await test_repo.save(index="test-document") assert await test_repo.save(index="test-document")
@@ -483,7 +492,9 @@ async def test_can_save_to_different_index(write_client):
) )
async def test_save_without_skip_empty_will_include_empty_fields(write_client) -> None: async def test_save_without_skip_empty_will_include_empty_fields(
write_client: Any,
) -> None:
test_repo = Repository(field_1=[], field_2=None, field_3={}, meta={"id": 42}) test_repo = Repository(field_1=[], field_2=None, field_3={}, meta={"id": 42})
assert await test_repo.save(index="test-document", skip_empty=False) assert await test_repo.save(index="test-document", skip_empty=False)
@@ -498,7 +509,7 @@ async def test_save_without_skip_empty_will_include_empty_fields(write_client) -
) )
async def test_delete(write_client) -> None: async def test_delete(write_client: Any) -> None:
await write_client.create( await write_client.create(
index="test-document", index="test-document",
id="opensearch-py", id="opensearch-py",
@@ -519,11 +530,11 @@ async def test_delete(write_client) -> None:
) )
async def test_search(data_client) -> None: async def test_search(data_client: Any) -> None:
assert await Repository.search().count() == 1 assert await Repository.search().count() == 1
async def test_search_returns_proper_doc_classes(data_client) -> None: async def test_search_returns_proper_doc_classes(data_client: Any) -> None:
result = await Repository.search().execute() result = await Repository.search().execute()
opensearch_repo = result.hits[0] opensearch_repo = result.hits[0]
@@ -532,8 +543,10 @@ async def test_search_returns_proper_doc_classes(data_client) -> None:
assert opensearch_repo.owner.name == "opensearch" assert opensearch_repo.owner.name == "opensearch"
async def test_refresh_mapping(data_client) -> None: async def test_refresh_mapping(data_client: Any) -> None:
class Commit(AsyncDocument): class Commit(AsyncDocument):
_index: Any
class Index: class Index:
name = "git" name = "git"
@@ -546,7 +559,7 @@ async def test_refresh_mapping(data_client) -> None:
assert isinstance(Commit._index._mapping["committed_date"], Date) assert isinstance(Commit._index._mapping["committed_date"], Date)
async def test_highlight_in_meta(data_client) -> None: async def test_highlight_in_meta(data_client: Any) -> None:
commit = ( commit = (
await Commit.search() await Commit.search()
.query("match", description="inverting") .query("match", description="inverting")
@@ -9,6 +9,7 @@
# GitHub history for details. # GitHub history for details.
from datetime import datetime from datetime import datetime
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -54,8 +55,8 @@ class MetricSearch(AsyncFacetedSearch):
} }
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
def commit_search_cls(opensearch_version): def commit_search_cls(opensearch_version: Any) -> Any:
interval_kwargs = {"fixed_interval": "1d"} interval_kwargs = {"fixed_interval": "1d"}
class CommitSearch(AsyncFacetedSearch): class CommitSearch(AsyncFacetedSearch):
@@ -79,8 +80,8 @@ def commit_search_cls(opensearch_version):
return CommitSearch return CommitSearch
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
def repo_search_cls(opensearch_version): def repo_search_cls(opensearch_version: Any) -> Any:
interval_type = "calendar_interval" interval_type = "calendar_interval"
class RepoSearch(AsyncFacetedSearch): class RepoSearch(AsyncFacetedSearch):
@@ -93,15 +94,15 @@ def repo_search_cls(opensearch_version):
), ),
} }
def search(self): def search(self) -> Any:
s = super(RepoSearch, self).search() s = super(RepoSearch, self).search()
return s.filter("term", commit_repo="repo") return s.filter("term", commit_repo="repo")
return RepoSearch return RepoSearch
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
def pr_search_cls(opensearch_version): def pr_search_cls(opensearch_version: Any) -> Any:
interval_type = "calendar_interval" interval_type = "calendar_interval"
class PRSearch(AsyncFacetedSearch): class PRSearch(AsyncFacetedSearch):
@@ -119,7 +120,7 @@ def pr_search_cls(opensearch_version):
return PRSearch return PRSearch
async def test_facet_with_custom_metric(data_client) -> None: async def test_facet_with_custom_metric(data_client: Any) -> None:
ms = MetricSearch() ms = MetricSearch()
r = await ms.execute() r = await ms.execute()
@@ -128,7 +129,7 @@ async def test_facet_with_custom_metric(data_client) -> None:
assert dates[0] == 1399038439000 assert dates[0] == 1399038439000
async def test_nested_facet(pull_request, pr_search_cls) -> None: async def test_nested_facet(pull_request: Any, pr_search_cls: Any) -> None:
prs = pr_search_cls() prs = pr_search_cls()
r = await prs.execute() r = await prs.execute()
@@ -136,7 +137,7 @@ async def test_nested_facet(pull_request, pr_search_cls) -> None:
assert [(datetime(2018, 1, 1, 0, 0), 1, False)] == r.facets.comments assert [(datetime(2018, 1, 1, 0, 0), 1, False)] == r.facets.comments
async def test_nested_facet_with_filter(pull_request, pr_search_cls) -> None: async def test_nested_facet_with_filter(pull_request: Any, pr_search_cls: Any) -> None:
prs = pr_search_cls(filters={"comments": datetime(2018, 1, 1, 0, 0)}) prs = pr_search_cls(filters={"comments": datetime(2018, 1, 1, 0, 0)})
r = await prs.execute() r = await prs.execute()
@@ -148,7 +149,7 @@ async def test_nested_facet_with_filter(pull_request, pr_search_cls) -> None:
assert not r.hits assert not r.hits
async def test_datehistogram_facet(data_client, repo_search_cls) -> None: async def test_datehistogram_facet(data_client: Any, repo_search_cls: Any) -> None:
rs = repo_search_cls() rs = repo_search_cls()
r = await rs.execute() r = await rs.execute()
@@ -156,7 +157,7 @@ async def test_datehistogram_facet(data_client, repo_search_cls) -> None:
assert [(datetime(2014, 3, 1, 0, 0), 1, False)] == r.facets.created assert [(datetime(2014, 3, 1, 0, 0), 1, False)] == r.facets.created
async def test_boolean_facet(data_client, repo_search_cls) -> None: async def test_boolean_facet(data_client: Any, repo_search_cls: Any) -> None:
rs = repo_search_cls() rs = repo_search_cls()
r = await rs.execute() r = await rs.execute()
@@ -167,7 +168,7 @@ async def test_boolean_facet(data_client, repo_search_cls) -> None:
async def test_empty_search_finds_everything( async def test_empty_search_finds_everything(
data_client, opensearch_version, commit_search_cls data_client: Any, opensearch_version: Any, commit_search_cls: Any
) -> None: ) -> None:
cs = commit_search_cls() cs = commit_search_cls()
r = await cs.execute() r = await cs.execute()
@@ -213,7 +214,7 @@ async def test_empty_search_finds_everything(
async def test_term_filters_are_shown_as_selected_and_data_is_filtered( async def test_term_filters_are_shown_as_selected_and_data_is_filtered(
data_client, commit_search_cls data_client: Any, commit_search_cls: Any
) -> None: ) -> None:
cs = commit_search_cls(filters={"files": "test_opensearchpy/test_dsl"}) cs = commit_search_cls(filters={"files": "test_opensearchpy/test_dsl"})
@@ -259,7 +260,7 @@ async def test_term_filters_are_shown_as_selected_and_data_is_filtered(
async def test_range_filters_are_shown_as_selected_and_data_is_filtered( async def test_range_filters_are_shown_as_selected_and_data_is_filtered(
data_client, commit_search_cls data_client: Any, commit_search_cls: Any
) -> None: ) -> None:
cs = commit_search_cls(filters={"deletions": "better"}) cs = commit_search_cls(filters={"deletions": "better"})
@@ -268,7 +269,7 @@ async def test_range_filters_are_shown_as_selected_and_data_is_filtered(
assert 19 == r.hits.total.value assert 19 == r.hits.total.value
async def test_pagination(data_client, commit_search_cls) -> None: async def test_pagination(data_client: Any, commit_search_cls: Any) -> None:
cs = commit_search_cls() cs = commit_search_cls()
cs = cs[0:20] cs = cs[0:20]
@@ -8,6 +8,8 @@
# Modifications Copyright OpenSearch Contributors. See # Modifications Copyright OpenSearch Contributors. See
# GitHub history for details. # GitHub history for details.
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -24,7 +26,7 @@ class Post(AsyncDocument):
published_from = Date() published_from = Date()
async def test_index_template_works(write_client) -> None: async def test_index_template_works(write_client: Any) -> None:
it = AsyncIndexTemplate("test-template", "test-*") it = AsyncIndexTemplate("test-template", "test-*")
it.document(Post) it.document(Post)
it.settings(number_of_replicas=0, number_of_shards=1) it.settings(number_of_replicas=0, number_of_shards=1)
@@ -45,7 +47,7 @@ async def test_index_template_works(write_client) -> None:
} == await write_client.indices.get_mapping(index="test-blog") } == await write_client.indices.get_mapping(index="test-blog")
async def test_index_can_be_saved_even_with_settings(write_client) -> None: async def test_index_can_be_saved_even_with_settings(write_client: Any) -> None:
i = AsyncIndex("test-blog", using=write_client) i = AsyncIndex("test-blog", using=write_client)
i.settings(number_of_shards=3, number_of_replicas=0) i.settings(number_of_shards=3, number_of_replicas=0)
await i.save() await i.save()
@@ -60,12 +62,14 @@ async def test_index_can_be_saved_even_with_settings(write_client) -> None:
) )
async def test_index_exists(data_client) -> None: async def test_index_exists(data_client: Any) -> None:
assert await AsyncIndex("git").exists() assert await AsyncIndex("git").exists()
assert not await AsyncIndex("not-there").exists() assert not await AsyncIndex("not-there").exists()
async def test_index_can_be_created_with_settings_and_mappings(write_client) -> None: async def test_index_can_be_created_with_settings_and_mappings(
write_client: Any,
) -> None:
i = AsyncIndex("test-blog", using=write_client) i = AsyncIndex("test-blog", using=write_client)
i.document(Post) i.document(Post)
i.settings(number_of_replicas=0, number_of_shards=1) i.settings(number_of_replicas=0, number_of_shards=1)
@@ -90,7 +94,7 @@ async def test_index_can_be_created_with_settings_and_mappings(write_client) ->
} }
async def test_delete(write_client) -> None: async def test_delete(write_client: Any) -> None:
await write_client.indices.create( await write_client.indices.create(
index="test-index", index="test-index",
body={"settings": {"number_of_replicas": 0, "number_of_shards": 1}}, body={"settings": {"number_of_replicas": 0, "number_of_shards": 1}},
@@ -101,9 +105,9 @@ async def test_delete(write_client) -> None:
assert not await write_client.indices.exists(index="test-index") assert not await write_client.indices.exists(index="test-index")
async def test_multiple_indices_with_same_doc_type_work(write_client) -> None: async def test_multiple_indices_with_same_doc_type_work(write_client: Any) -> None:
i1 = AsyncIndex("test-index-1", using=write_client) i1: Any = AsyncIndex("test-index-1", using=write_client)
i2 = AsyncIndex("test-index-2", using=write_client) i2: Any = AsyncIndex("test-index-2", using=write_client)
for i in i1, i2: for i in i1, i2:
i.document(Post) i.document(Post)
@@ -8,6 +8,8 @@
# Modifications Copyright OpenSearch Contributors. See # Modifications Copyright OpenSearch Contributors. See
# GitHub history for details. # GitHub history for details.
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
from pytest import raises from pytest import raises
@@ -19,7 +21,7 @@ from opensearchpy.helpers import analysis
pytestmark: MarkDecorator = pytest.mark.asyncio pytestmark: MarkDecorator = pytest.mark.asyncio
async def test_mapping_saved_into_opensearch(write_client) -> None: async def test_mapping_saved_into_opensearch(write_client: Any) -> None:
m = mapping.AsyncMapping() m = mapping.AsyncMapping()
m.field( m.field(
"name", "text", analyzer=analysis.analyzer("my_analyzer", tokenizer="keyword") "name", "text", analyzer=analysis.analyzer("my_analyzer", tokenizer="keyword")
@@ -40,7 +42,7 @@ async def test_mapping_saved_into_opensearch(write_client) -> None:
async def test_mapping_saved_into_opensearch_when_index_already_exists_closed( async def test_mapping_saved_into_opensearch_when_index_already_exists_closed(
write_client, write_client: Any,
) -> None: ) -> None:
m = mapping.AsyncMapping() m = mapping.AsyncMapping()
m.field( m.field(
@@ -65,7 +67,7 @@ async def test_mapping_saved_into_opensearch_when_index_already_exists_closed(
async def test_mapping_saved_into_opensearch_when_index_already_exists_with_analysis( async def test_mapping_saved_into_opensearch_when_index_already_exists_with_analysis(
write_client, write_client: Any,
) -> None: ) -> None:
m = mapping.AsyncMapping() m = mapping.AsyncMapping()
analyzer = analysis.analyzer("my_analyzer", tokenizer="keyword") analyzer = analysis.analyzer("my_analyzer", tokenizer="keyword")
@@ -95,7 +97,7 @@ async def test_mapping_saved_into_opensearch_when_index_already_exists_with_anal
} == await write_client.indices.get_mapping(index="test-mapping") } == await write_client.indices.get_mapping(index="test-mapping")
async def test_mapping_gets_updated_from_opensearch(write_client): async def test_mapping_gets_updated_from_opensearch(write_client: Any) -> None:
await write_client.indices.create( await write_client.indices.create(
index="test-mapping", index="test-mapping",
body={ body={
@@ -10,6 +10,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
from pytest import raises from pytest import raises
@@ -29,7 +31,7 @@ class Repository(AsyncDocument):
tags = Keyword() tags = Keyword()
@classmethod @classmethod
def search(cls): def search(cls, using: Any = None, index: Any = None) -> Any:
return super(Repository, cls).search().filter("term", commit_repo="repo") return super(Repository, cls).search().filter("term", commit_repo="repo")
class Index: class Index:
@@ -41,7 +43,7 @@ class Commit(AsyncDocument):
name = "flat-git" name = "flat-git"
async def test_filters_aggregation_buckets_are_accessible(data_client) -> None: async def test_filters_aggregation_buckets_are_accessible(data_client: Any) -> None:
has_tests_query = Q("term", files="test_opensearchpy/test_dsl") has_tests_query = Q("term", files="test_opensearchpy/test_dsl")
s = Commit.search()[0:0] s = Commit.search()[0:0]
s.aggs.bucket("top_authors", "terms", field="author.name.raw").bucket( s.aggs.bucket("top_authors", "terms", field="author.name.raw").bucket(
@@ -62,7 +64,7 @@ async def test_filters_aggregation_buckets_are_accessible(data_client) -> None:
) )
async def test_top_hits_are_wrapped_in_response(data_client) -> None: async def test_top_hits_are_wrapped_in_response(data_client: Any) -> None:
s = Commit.search()[0:0] s = Commit.search()[0:0]
s.aggs.bucket("top_authors", "terms", field="author.name.raw").metric( s.aggs.bucket("top_authors", "terms", field="author.name.raw").metric(
"top_commits", "top_hits", size=5 "top_commits", "top_hits", size=5
@@ -78,7 +80,7 @@ async def test_top_hits_are_wrapped_in_response(data_client) -> None:
assert isinstance(hits[0], Commit) assert isinstance(hits[0], Commit)
async def test_inner_hits_are_wrapped_in_response(data_client) -> None: async def test_inner_hits_are_wrapped_in_response(data_client: Any) -> None:
s = AsyncSearch(index="git")[0:1].query( s = AsyncSearch(index="git")[0:1].query(
"has_parent", parent_type="repo", inner_hits={}, query=Q("match_all") "has_parent", parent_type="repo", inner_hits={}, query=Q("match_all")
) )
@@ -89,7 +91,7 @@ async def test_inner_hits_are_wrapped_in_response(data_client) -> None:
assert repr(commit.meta.inner_hits.repo[0]).startswith("<Hit(git/opensearch-py): ") assert repr(commit.meta.inner_hits.repo[0]).startswith("<Hit(git/opensearch-py): ")
async def test_scan_respects_doc_types(data_client) -> None: async def test_scan_respects_doc_types(data_client: Any) -> None:
result = Repository.search().scan() result = Repository.search().scan()
repos = await get_result(result) repos = await get_result(result)
@@ -98,7 +100,7 @@ async def test_scan_respects_doc_types(data_client) -> None:
assert repos[0].organization == "opensearch" assert repos[0].organization == "opensearch"
async def test_scan_iterates_through_all_docs(data_client) -> None: async def test_scan_iterates_through_all_docs(data_client: Any) -> None:
s = AsyncSearch(index="flat-git") s = AsyncSearch(index="flat-git")
result = s.scan() result = s.scan()
commits = await get_result(result) commits = await get_result(result)
@@ -107,14 +109,14 @@ async def test_scan_iterates_through_all_docs(data_client) -> None:
assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits} assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits}
async def get_result(b): async def get_result(b: Any) -> Any:
a = [] a = []
async for i in b: async for i in b:
a.append(i) a.append(i)
return a return a
async def test_multi_search(data_client) -> None: async def test_multi_search(data_client: Any) -> None:
s1 = Repository.search() s1 = Repository.search()
s2 = AsyncSearch(index="flat-git") s2 = AsyncSearch(index="flat-git")
@@ -131,7 +133,7 @@ async def test_multi_search(data_client) -> None:
assert r2._search is s2 assert r2._search is s2
async def test_multi_missing(data_client) -> None: async def test_multi_missing(data_client: Any) -> None:
s1 = Repository.search() s1 = Repository.search()
s2 = AsyncSearch(index="flat-git") s2 = AsyncSearch(index="flat-git")
s3 = AsyncSearch(index="does_not_exist") s3 = AsyncSearch(index="does_not_exist")
@@ -154,7 +156,7 @@ async def test_multi_missing(data_client) -> None:
assert r3 is None assert r3 is None
async def test_raw_subfield_can_be_used_in_aggs(data_client) -> None: async def test_raw_subfield_can_be_used_in_aggs(data_client: Any) -> None:
s = AsyncSearch(index="git")[0:0] s = AsyncSearch(index="git")[0:0]
s.aggs.bucket("authors", "terms", field="author.name.raw", size=1) s.aggs.bucket("authors", "terms", field="author.name.raw", size=1)
r = await s.execute() r = await s.execute()
@@ -8,6 +8,8 @@
# Modifications Copyright OpenSearch Contributors. See # Modifications Copyright OpenSearch Contributors. See
# GitHub history for details. # GitHub history for details.
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -17,7 +19,9 @@ from opensearchpy.helpers.search import Q
pytestmark: MarkDecorator = pytest.mark.asyncio pytestmark: MarkDecorator = pytest.mark.asyncio
async def test_update_by_query_no_script(write_client, setup_ubq_tests) -> None: async def test_update_by_query_no_script(
write_client: Any, setup_ubq_tests: Any
) -> None:
index = setup_ubq_tests index = setup_ubq_tests
ubq = ( ubq = (
@@ -36,7 +40,9 @@ async def test_update_by_query_no_script(write_client, setup_ubq_tests) -> None:
assert response.success() assert response.success()
async def test_update_by_query_with_script(write_client, setup_ubq_tests) -> None: async def test_update_by_query_with_script(
write_client: Any, setup_ubq_tests: Any
) -> None:
index = setup_ubq_tests index = setup_ubq_tests
ubq = ( ubq = (
@@ -53,7 +59,9 @@ async def test_update_by_query_with_script(write_client, setup_ubq_tests) -> Non
assert response.version_conflicts == 0 assert response.version_conflicts == 0
async def test_delete_by_query_with_script(write_client, setup_ubq_tests) -> None: async def test_delete_by_query_with_script(
write_client: Any, setup_ubq_tests: Any
) -> None:
index = setup_ubq_tests index = setup_ubq_tests
ubq = ( ubq = (
@@ -28,7 +28,7 @@ class TestAlertingPlugin(AsyncOpenSearchTestCase):
(OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)),
"Plugin not supported for opensearch version", "Plugin not supported for opensearch version",
) )
async def test_create_destination(self): async def test_create_destination(self) -> None:
# Test to create alert destination # Test to create alert destination
dummy_destination = { dummy_destination = {
"name": "my-destination", "name": "my-destination",
@@ -59,7 +59,7 @@ class TestAlertingPlugin(AsyncOpenSearchTestCase):
(OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)),
"Plugin not supported for opensearch version", "Plugin not supported for opensearch version",
) )
async def test_create_monitor(self): async def test_create_monitor(self) -> None:
# Create a dummy destination # Create a dummy destination
await self.test_create_destination() await self.test_create_destination()
@@ -33,6 +33,7 @@ clients.
""" """
import inspect import inspect
import warnings import warnings
from typing import Any
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -53,14 +54,14 @@ pytestmark: MarkDecorator = pytest.mark.asyncio
OPENSEARCH_VERSION = None OPENSEARCH_VERSION = None
async def await_if_coro(x): async def await_if_coro(x: Any) -> Any:
if inspect.iscoroutine(x): if inspect.iscoroutine(x):
return await x return await x
return x return x
class AsyncYamlRunner(YamlRunner): class AsyncYamlRunner(YamlRunner):
async def setup(self): async def setup(self) -> None:
# Pull skips from individual tests to not do unnecessary setup. # Pull skips from individual tests to not do unnecessary setup.
skip_code = [] skip_code = []
for action in self._run_code: for action in self._run_code:
@@ -78,12 +79,12 @@ class AsyncYamlRunner(YamlRunner):
if self._setup_code: if self._setup_code:
await self.run_code(self._setup_code) await self.run_code(self._setup_code)
async def teardown(self) -> None: async def teardown(self) -> Any:
if self._teardown_code: if self._teardown_code:
self.section("teardown") self.section("teardown")
await self.run_code(self._teardown_code) await self.run_code(self._teardown_code)
async def opensearch_version(self): async def opensearch_version(self) -> Any:
global OPENSEARCH_VERSION global OPENSEARCH_VERSION
if OPENSEARCH_VERSION is None: if OPENSEARCH_VERSION is None:
version_string = (await self.client.info())["version"]["number"] version_string = (await self.client.info())["version"]["number"]
@@ -93,10 +94,10 @@ class AsyncYamlRunner(YamlRunner):
OPENSEARCH_VERSION = tuple(int(v) if v.isdigit() else 999 for v in version) OPENSEARCH_VERSION = tuple(int(v) if v.isdigit() else 999 for v in version)
return OPENSEARCH_VERSION return OPENSEARCH_VERSION
def section(self, name) -> None: def section(self, name: str) -> None:
print(("=" * 10) + " " + name + " " + ("=" * 10)) print(("=" * 10) + " " + name + " " + ("=" * 10))
async def run(self) -> None: async def run(self) -> Any:
try: try:
await self.setup() await self.setup()
self.section("test") self.section("test")
@@ -107,7 +108,7 @@ class AsyncYamlRunner(YamlRunner):
except Exception: except Exception:
pass pass
async def run_code(self, test) -> None: async def run_code(self, test: Any) -> Any:
"""Execute an instruction based on its type.""" """Execute an instruction based on its type."""
for action in test: for action in test:
assert len(action) == 1 assert len(action) == 1
@@ -119,7 +120,7 @@ class AsyncYamlRunner(YamlRunner):
else: else:
raise RuntimeError("Invalid action type %r" % (action_type,)) raise RuntimeError("Invalid action type %r" % (action_type,))
async def run_do(self, action) -> None: async def run_do(self, action: Any) -> Any:
api = self.client api = self.client
headers = action.pop("headers", None) headers = action.pop("headers", None)
catch = action.pop("catch", None) catch = action.pop("catch", None)
@@ -171,7 +172,7 @@ class AsyncYamlRunner(YamlRunner):
# Filter out warnings raised by other components. # Filter out warnings raised by other components.
caught_warnings = [ caught_warnings = [
str(w.message) str(w.message) # type: ignore
for w in caught_warnings for w in caught_warnings
if w.category == OpenSearchWarning if w.category == OpenSearchWarning
and str(w.message) not in allowed_warnings and str(w.message) not in allowed_warnings
@@ -179,13 +180,13 @@ class AsyncYamlRunner(YamlRunner):
# Sorting removes the issue with order raised. We only care about # Sorting removes the issue with order raised. We only care about
# if all warnings are raised in the single API call. # if all warnings are raised in the single API call.
if warn and sorted(warn) != sorted(caught_warnings): if warn and sorted(warn) != sorted(caught_warnings): # type: ignore
raise AssertionError( raise AssertionError(
"Expected warnings not equal to actual warnings: expected=%r actual=%r" "Expected warnings not equal to actual warnings: expected=%r actual=%r"
% (warn, caught_warnings) % (warn, caught_warnings)
) )
async def run_skip(self, skip) -> None: async def run_skip(self, skip: Any) -> Any:
if "features" in skip: if "features" in skip:
features = skip["features"] features = skip["features"]
if not isinstance(features, (tuple, list)): if not isinstance(features, (tuple, list)):
@@ -205,19 +206,19 @@ class AsyncYamlRunner(YamlRunner):
if min_version <= (await self.opensearch_version()) <= max_version: if min_version <= (await self.opensearch_version()) <= max_version:
pytest.skip(reason) pytest.skip(reason)
async def _feature_enabled(self, name) -> bool: async def _feature_enabled(self, name: str) -> Any:
return False return False
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
def async_runner(async_client): def async_runner(async_client: Any) -> AsyncYamlRunner:
return AsyncYamlRunner(async_client) return AsyncYamlRunner(async_client)
if RUN_ASYNC_REST_API_TESTS: if RUN_ASYNC_REST_API_TESTS:
@pytest.mark.parametrize("test_spec", YAML_TEST_SPECS) @pytest.mark.parametrize("test_spec", YAML_TEST_SPECS) # type: ignore
async def test_rest_api_spec(test_spec, async_runner) -> None: async def test_rest_api_spec(test_spec: Any, async_runner: Any) -> None:
if test_spec.get("skip", False): if test_spec.get("skip", False):
pytest.skip("Manually skipped in 'SKIP_TESTS'") pytest.skip("Manually skipped in 'SKIP_TESTS'")
async_runner.use_spec(test_spec) async_runner.use_spec(test_spec)
@@ -11,7 +11,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from unittest import IsolatedAsyncioTestCase from unittest import IsolatedAsyncioTestCase # type: ignore
import pytest import pytest
from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import MarkDecorator
@@ -23,7 +23,7 @@ from opensearchpy.exceptions import NotFoundError
pytestmark: MarkDecorator = pytest.mark.asyncio pytestmark: MarkDecorator = pytest.mark.asyncio
class TestSecurityPlugin(IsolatedAsyncioTestCase): class TestSecurityPlugin(IsolatedAsyncioTestCase): # type: ignore
ROLE_NAME = "test-role" ROLE_NAME = "test-role"
ROLE_CONTENT = { ROLE_CONTENT = {
"cluster_permissions": ["cluster_monitor"], "cluster_permissions": ["cluster_monitor"],
@@ -123,7 +123,7 @@ class TestSecurityPlugin(IsolatedAsyncioTestCase):
else: else:
assert False assert False
async def test_create_user_with_role(self): async def test_create_user_with_role(self) -> None:
await self.test_create_role() await self.test_create_role()
# Test to create user # Test to create user
+6 -6
View File
@@ -18,7 +18,7 @@ pytestmark: MarkDecorator = pytest.mark.asyncio
class TestAsyncSigner: class TestAsyncSigner:
def mock_session(self): def mock_session(self) -> Mock:
access_key = uuid.uuid4().hex access_key = uuid.uuid4().hex
secret_key = uuid.uuid4().hex secret_key = uuid.uuid4().hex
token = uuid.uuid4().hex token = uuid.uuid4().hex
@@ -37,7 +37,7 @@ class TestAsyncSigner:
from opensearchpy.helpers.asyncsigner import AWSV4SignerAsyncAuth from opensearchpy.helpers.asyncsigner import AWSV4SignerAsyncAuth
auth = AWSV4SignerAsyncAuth(self.mock_session(), region) auth = AWSV4SignerAsyncAuth(self.mock_session(), region)
headers = auth("GET", "http://localhost", {}, {}) headers = auth("GET", "http://localhost")
assert "Authorization" in headers assert "Authorization" in headers
assert "X-Amz-Date" in headers assert "X-Amz-Date" in headers
assert "X-Amz-Security-Token" in headers assert "X-Amz-Security-Token" in headers
@@ -48,7 +48,7 @@ class TestAsyncSigner:
from opensearchpy.helpers.asyncsigner import AWSV4SignerAsyncAuth from opensearchpy.helpers.asyncsigner import AWSV4SignerAsyncAuth
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
AWSV4SignerAsyncAuth(session, None) AWSV4SignerAsyncAuth(session, None) # type: ignore
assert str(e.value) == "Region cannot be empty" assert str(e.value) == "Region cannot be empty"
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
@@ -71,7 +71,7 @@ class TestAsyncSigner:
from opensearchpy.helpers.asyncsigner import AWSV4SignerAsyncAuth from opensearchpy.helpers.asyncsigner import AWSV4SignerAsyncAuth
auth = AWSV4SignerAsyncAuth(self.mock_session(), region, service) auth = AWSV4SignerAsyncAuth(self.mock_session(), region, service)
headers = auth("GET", "http://localhost", {}, {}) headers = auth("GET", "http://localhost")
assert "Authorization" in headers assert "Authorization" in headers
assert "X-Amz-Date" in headers assert "X-Amz-Date" in headers
assert "X-Amz-Security-Token" in headers assert "X-Amz-Security-Token" in headers
@@ -79,7 +79,7 @@ class TestAsyncSigner:
class TestAsyncSignerWithFrozenCredentials(TestAsyncSigner): class TestAsyncSignerWithFrozenCredentials(TestAsyncSigner):
def mock_session(self, disable_get_frozen: bool = True): def mock_session(self, disable_get_frozen: bool = True) -> Mock:
access_key = uuid.uuid4().hex access_key = uuid.uuid4().hex
secret_key = uuid.uuid4().hex secret_key = uuid.uuid4().hex
token = uuid.uuid4().hex token = uuid.uuid4().hex
@@ -99,7 +99,7 @@ class TestAsyncSignerWithFrozenCredentials(TestAsyncSigner):
mock_session = self.mock_session() mock_session = self.mock_session()
auth = AWSV4SignerAsyncAuth(mock_session, region) auth = AWSV4SignerAsyncAuth(mock_session, region)
headers = auth("GET", "http://localhost", {}, {}) headers = auth("GET", "http://localhost")
assert "Authorization" in headers assert "Authorization" in headers
assert "X-Amz-Date" in headers assert "X-Amz-Date" in headers
assert "X-Amz-Security-Token" in headers assert "X-Amz-Security-Token" in headers
+71 -59
View File
@@ -45,16 +45,16 @@ pytestmark: MarkDecorator = pytest.mark.asyncio
class DummyConnection(Connection): class DummyConnection(Connection):
def __init__(self, **kwargs) -> None: def __init__(self, **kwargs: Any) -> None:
self.exception = kwargs.pop("exception", None) self.exception = kwargs.pop("exception", None)
self.status, self.data = kwargs.pop("status", 200), kwargs.pop("data", "{}") self.status, self.data = kwargs.pop("status", 200), kwargs.pop("data", "{}")
self.headers = kwargs.pop("headers", {}) self.headers = kwargs.pop("headers", {})
self.delay = kwargs.pop("delay", 0) self.delay = kwargs.pop("delay", 0)
self.calls = [] self.calls: Any = []
self.closed = False self.closed = False
super(DummyConnection, self).__init__(**kwargs) super(DummyConnection, self).__init__(**kwargs)
async def perform_request(self, *args, **kwargs) -> Any: async def perform_request(self, *args: Any, **kwargs: Any) -> Any:
if self.closed: if self.closed:
raise RuntimeError("This connection is closed") raise RuntimeError("This connection is closed")
if self.delay: if self.delay:
@@ -123,15 +123,15 @@ CLUSTER_NODES_7x_PUBLISH_HOST = """{
class TestTransport: class TestTransport:
async def test_single_connection_uses_dummy_connection_pool(self) -> None: async def test_single_connection_uses_dummy_connection_pool(self) -> None:
t = AsyncTransport([{}]) t1: Any = AsyncTransport([{}])
await t._async_call() await t1._async_call()
assert isinstance(t.connection_pool, DummyConnectionPool) assert isinstance(t1.connection_pool, DummyConnectionPool)
t = AsyncTransport([{"host": "localhost"}]) t2: Any = AsyncTransport([{"host": "localhost"}])
await t._async_call() await t2._async_call()
assert isinstance(t.connection_pool, DummyConnectionPool) assert isinstance(t2.connection_pool, DummyConnectionPool)
async def test_request_timeout_extracted_from_params_and_passed(self) -> None: async def test_request_timeout_extracted_from_params_and_passed(self) -> None:
t = AsyncTransport([{}], connection_class=DummyConnection) t: Any = AsyncTransport([{}], connection_class=DummyConnection)
await t.perform_request("GET", "/", params={"request_timeout": 42}) await t.perform_request("GET", "/", params={"request_timeout": 42})
assert 1 == len(t.get_connection().calls) assert 1 == len(t.get_connection().calls)
@@ -143,7 +143,7 @@ class TestTransport:
} == t.get_connection().calls[0][1] } == t.get_connection().calls[0][1]
async def test_timeout_extracted_from_params_and_passed(self) -> None: async def test_timeout_extracted_from_params_and_passed(self) -> None:
t = AsyncTransport([{}], connection_class=DummyConnection) t: Any = AsyncTransport([{}], connection_class=DummyConnection)
await t.perform_request("GET", "/", params={"timeout": 84}) await t.perform_request("GET", "/", params={"timeout": 84})
assert 1 == len(t.get_connection().calls) assert 1 == len(t.get_connection().calls)
@@ -154,8 +154,10 @@ class TestTransport:
"headers": None, "headers": None,
} == t.get_connection().calls[0][1] } == t.get_connection().calls[0][1]
async def test_opaque_id(self): async def test_opaque_id(self) -> None:
t = AsyncTransport([{}], opaque_id="app-1", connection_class=DummyConnection) t: Any = AsyncTransport(
[{}], opaque_id="app-1", connection_class=DummyConnection
)
await t.perform_request("GET", "/") await t.perform_request("GET", "/")
assert 1 == len(t.get_connection().calls) assert 1 == len(t.get_connection().calls)
@@ -176,8 +178,8 @@ class TestTransport:
"headers": {"x-opaque-id": "request-1"}, "headers": {"x-opaque-id": "request-1"},
} == t.get_connection().calls[1][1] } == t.get_connection().calls[1][1]
async def test_request_with_custom_user_agent_header(self): async def test_request_with_custom_user_agent_header(self) -> None:
t = AsyncTransport([{}], connection_class=DummyConnection) t: Any = AsyncTransport([{}], connection_class=DummyConnection)
await t.perform_request( await t.perform_request(
"GET", "/", headers={"user-agent": "my-custom-value/1.2.3"} "GET", "/", headers={"user-agent": "my-custom-value/1.2.3"}
@@ -190,7 +192,7 @@ class TestTransport:
} == t.get_connection().calls[0][1] } == t.get_connection().calls[0][1]
async def test_send_get_body_as_source(self) -> None: async def test_send_get_body_as_source(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{}], send_get_body_as="source", connection_class=DummyConnection [{}], send_get_body_as="source", connection_class=DummyConnection
) )
@@ -199,7 +201,7 @@ class TestTransport:
assert ("GET", "/", {"source": "{}"}, None) == t.get_connection().calls[0][0] assert ("GET", "/", {"source": "{}"}, None) == t.get_connection().calls[0][0]
async def test_send_get_body_as_post(self) -> None: async def test_send_get_body_as_post(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{}], send_get_body_as="POST", connection_class=DummyConnection [{}], send_get_body_as="POST", connection_class=DummyConnection
) )
@@ -208,7 +210,7 @@ class TestTransport:
assert ("POST", "/", None, b"{}") == t.get_connection().calls[0][0] assert ("POST", "/", None, b"{}") == t.get_connection().calls[0][0]
async def test_body_gets_encoded_into_bytes(self) -> None: async def test_body_gets_encoded_into_bytes(self) -> None:
t = AsyncTransport([{}], connection_class=DummyConnection) t: Any = AsyncTransport([{}], connection_class=DummyConnection)
await t.perform_request("GET", "/", body="你好") await t.perform_request("GET", "/", body="你好")
assert 1 == len(t.get_connection().calls) assert 1 == len(t.get_connection().calls)
@@ -220,7 +222,7 @@ class TestTransport:
) == t.get_connection().calls[0][0] ) == t.get_connection().calls[0][0]
async def test_body_bytes_get_passed_untouched(self) -> None: async def test_body_bytes_get_passed_untouched(self) -> None:
t = AsyncTransport([{}], connection_class=DummyConnection) t: Any = AsyncTransport([{}], connection_class=DummyConnection)
body = b"\xe4\xbd\xa0\xe5\xa5\xbd" body = b"\xe4\xbd\xa0\xe5\xa5\xbd"
await t.perform_request("GET", "/", body=body) await t.perform_request("GET", "/", body=body)
@@ -228,7 +230,7 @@ class TestTransport:
assert ("GET", "/", None, body) == t.get_connection().calls[0][0] assert ("GET", "/", None, body) == t.get_connection().calls[0][0]
async def test_body_surrogates_replaced_encoded_into_bytes(self) -> None: async def test_body_surrogates_replaced_encoded_into_bytes(self) -> None:
t = AsyncTransport([{}], connection_class=DummyConnection) t: Any = AsyncTransport([{}], connection_class=DummyConnection)
await t.perform_request("GET", "/", body="你好\uda6a") await t.perform_request("GET", "/", body="你好\uda6a")
assert 1 == len(t.get_connection().calls) assert 1 == len(t.get_connection().calls)
@@ -240,36 +242,36 @@ class TestTransport:
) == t.get_connection().calls[0][0] ) == t.get_connection().calls[0][0]
async def test_kwargs_passed_on_to_connections(self) -> None: async def test_kwargs_passed_on_to_connections(self) -> None:
t = AsyncTransport([{"host": "google.com"}], port=123) t: Any = AsyncTransport([{"host": "google.com"}], port=123)
await t._async_call() await t._async_call()
assert 1 == len(t.connection_pool.connections) assert 1 == len(t.connection_pool.connections)
assert "http://google.com:123" == t.connection_pool.connections[0].host assert "http://google.com:123" == t.connection_pool.connections[0].host
async def test_kwargs_passed_on_to_connection_pool(self) -> None: async def test_kwargs_passed_on_to_connection_pool(self) -> None:
dt = object() dt = object()
t = AsyncTransport([{}, {}], dead_timeout=dt) t: Any = AsyncTransport([{}, {}], dead_timeout=dt)
await t._async_call() await t._async_call()
assert dt is t.connection_pool.dead_timeout assert dt is t.connection_pool.dead_timeout
async def test_custom_connection_class(self) -> None: async def test_custom_connection_class(self) -> None:
class MyConnection(object): class MyConnection(object):
def __init__(self, **kwargs): def __init__(self, **kwargs: Any) -> None:
self.kwargs = kwargs self.kwargs = kwargs
t = AsyncTransport([{}], connection_class=MyConnection) t: Any = AsyncTransport([{}], connection_class=MyConnection)
await t._async_call() await t._async_call()
assert 1 == len(t.connection_pool.connections) assert 1 == len(t.connection_pool.connections)
assert isinstance(t.connection_pool.connections[0], MyConnection) assert isinstance(t.connection_pool.connections[0], MyConnection)
async def test_add_connection(self) -> None: async def test_add_connection(self) -> None:
t = AsyncTransport([{}], randomize_hosts=False) t: Any = AsyncTransport([{}], randomize_hosts=False)
t.add_connection({"host": "google.com", "port": 1234}) t.add_connection({"host": "google.com", "port": 1234})
assert 2 == len(t.connection_pool.connections) assert 2 == len(t.connection_pool.connections)
assert "http://google.com:1234" == t.connection_pool.connections[1].host assert "http://google.com:1234" == t.connection_pool.connections[1].host
async def test_request_will_fail_after_X_retries(self) -> None: async def test_request_will_fail_after_X_retries(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{"exception": ConnectionError("abandon ship")}], [{"exception": ConnectionError("abandon ship")}],
connection_class=DummyConnection, connection_class=DummyConnection,
) )
@@ -284,7 +286,7 @@ class TestTransport:
assert 4 == len(t.get_connection().calls) assert 4 == len(t.get_connection().calls)
async def test_failed_connection_will_be_marked_as_dead(self) -> None: async def test_failed_connection_will_be_marked_as_dead(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{"exception": ConnectionError("abandon ship")}] * 2, [{"exception": ConnectionError("abandon ship")}] * 2,
connection_class=DummyConnection, connection_class=DummyConnection,
) )
@@ -302,7 +304,7 @@ class TestTransport:
self, self,
) -> None: ) -> None:
for method in ("GET", "HEAD"): for method in ("GET", "HEAD"):
t = AsyncTransport([{}, {}], connection_class=DummyConnection) t: Any = AsyncTransport([{}, {}], connection_class=DummyConnection)
await t._async_call() await t._async_call()
con1 = t.connection_pool.get_connection() con1 = t.connection_pool.get_connection()
con2 = t.connection_pool.get_connection() con2 = t.connection_pool.get_connection()
@@ -314,7 +316,9 @@ class TestTransport:
assert 1 == len(t.connection_pool.dead_count) assert 1 == len(t.connection_pool.dead_count)
async def test_sniff_will_use_seed_connections(self) -> None: async def test_sniff_will_use_seed_connections(self) -> None:
t = AsyncTransport([{"data": CLUSTER_NODES}], connection_class=DummyConnection) t: Any = AsyncTransport(
[{"data": CLUSTER_NODES}], connection_class=DummyConnection
)
await t._async_call() await t._async_call()
t.set_connections([{"data": "invalid"}]) t.set_connections([{"data": "invalid"}])
@@ -323,7 +327,7 @@ class TestTransport:
assert "http://1.1.1.1:123" == t.get_connection().host assert "http://1.1.1.1:123" == t.get_connection().host
async def test_sniff_on_start_fetches_and_uses_nodes_list(self) -> None: async def test_sniff_on_start_fetches_and_uses_nodes_list(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{"data": CLUSTER_NODES}], [{"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_on_start=True, sniff_on_start=True,
@@ -335,7 +339,7 @@ class TestTransport:
assert "http://1.1.1.1:123" == t.get_connection().host assert "http://1.1.1.1:123" == t.get_connection().host
async def test_sniff_on_start_ignores_sniff_timeout(self) -> None: async def test_sniff_on_start_ignores_sniff_timeout(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{"data": CLUSTER_NODES}], [{"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_on_start=True, sniff_on_start=True,
@@ -349,7 +353,7 @@ class TestTransport:
].calls[0] ].calls[0]
async def test_sniff_uses_sniff_timeout(self) -> None: async def test_sniff_uses_sniff_timeout(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{"data": CLUSTER_NODES}], [{"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_timeout=42, sniff_timeout=42,
@@ -361,8 +365,8 @@ class TestTransport:
0 0
].calls[0] ].calls[0]
async def test_sniff_reuses_connection_instances_if_possible(self): async def test_sniff_reuses_connection_instances_if_possible(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{"data": CLUSTER_NODES}, {"host": "1.1.1.1", "port": 123}], [{"data": CLUSTER_NODES}, {"host": "1.1.1.1", "port": 123}],
connection_class=DummyConnection, connection_class=DummyConnection,
randomize_hosts=False, randomize_hosts=False,
@@ -375,8 +379,8 @@ class TestTransport:
assert 1 == len(t.connection_pool.connections) assert 1 == len(t.connection_pool.connections)
assert connection is t.get_connection() assert connection is t.get_connection()
async def test_sniff_on_fail_triggers_sniffing_on_fail(self): async def test_sniff_on_fail_triggers_sniffing_on_fail(self) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{"exception": ConnectionError("abandon ship")}, {"data": CLUSTER_NODES}], [{"exception": ConnectionError("abandon ship")}, {"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_on_connection_fail=True, sniff_on_connection_fail=True,
@@ -398,9 +402,11 @@ class TestTransport:
assert "http://1.1.1.1:123" == t.get_connection().host assert "http://1.1.1.1:123" == t.get_connection().host
@patch("opensearchpy._async.transport.AsyncTransport.sniff_hosts") @patch("opensearchpy._async.transport.AsyncTransport.sniff_hosts")
async def test_sniff_on_fail_failing_does_not_prevent_retires(self, sniff_hosts): async def test_sniff_on_fail_failing_does_not_prevent_retires(
self, sniff_hosts: Any
) -> None:
sniff_hosts.side_effect = [TransportError("sniff failed")] sniff_hosts.side_effect = [TransportError("sniff failed")]
t = AsyncTransport( t: Any = AsyncTransport(
[{"exception": ConnectionError("abandon ship")}, {"data": CLUSTER_NODES}], [{"exception": ConnectionError("abandon ship")}, {"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_on_connection_fail=True, sniff_on_connection_fail=True,
@@ -416,8 +422,8 @@ class TestTransport:
assert 1 == len(conn_err.calls) assert 1 == len(conn_err.calls)
assert 1 == len(conn_data.calls) assert 1 == len(conn_data.calls)
async def test_sniff_after_n_seconds(self, event_loop) -> None: async def test_sniff_after_n_seconds(self, event_loop: Any) -> None:
t = AsyncTransport( t: Any = AsyncTransport(
[{"data": CLUSTER_NODES}], [{"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniffer_timeout=5, sniffer_timeout=5,
@@ -440,7 +446,7 @@ class TestTransport:
async def test_sniff_7x_publish_host(self) -> None: async def test_sniff_7x_publish_host(self) -> None:
# Test the response shaped when a 7.x node has publish_host set # Test the response shaped when a 7.x node has publish_host set
# and the returend data is shaped in the fqdn/ip:port format. # and the returend data is shaped in the fqdn/ip:port format.
t = AsyncTransport( t: Any = AsyncTransport(
[{"data": CLUSTER_NODES_7x_PUBLISH_HOST}], [{"data": CLUSTER_NODES_7x_PUBLISH_HOST}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_timeout=42, sniff_timeout=42,
@@ -454,22 +460,24 @@ class TestTransport:
} }
async def test_transport_close_closes_all_pool_connections(self) -> None: async def test_transport_close_closes_all_pool_connections(self) -> None:
t = AsyncTransport([{}], connection_class=DummyConnection) t1: Any = AsyncTransport([{}], connection_class=DummyConnection)
await t._async_call() await t1._async_call()
assert not any([conn.closed for conn in t.connection_pool.connections]) assert not any([conn.closed for conn in t1.connection_pool.connections])
await t.close() await t1.close()
assert all([conn.closed for conn in t.connection_pool.connections]) assert all([conn.closed for conn in t1.connection_pool.connections])
t = AsyncTransport([{}, {}], connection_class=DummyConnection) t2: Any = AsyncTransport([{}, {}], connection_class=DummyConnection)
await t._async_call() await t2._async_call()
assert not any([conn.closed for conn in t.connection_pool.connections]) assert not any([conn.closed for conn in t2.connection_pool.connections])
await t.close() await t2.close()
assert all([conn.closed for conn in t.connection_pool.connections]) assert all([conn.closed for conn in t2.connection_pool.connections])
async def test_sniff_on_start_error_if_no_sniffed_hosts(self, event_loop) -> None: async def test_sniff_on_start_error_if_no_sniffed_hosts(
t = AsyncTransport( self, event_loop: Any
) -> None:
t: Any = AsyncTransport(
[ [
{"data": ""}, {"data": ""},
{"data": ""}, {"data": ""},
@@ -485,8 +493,10 @@ class TestTransport:
await t._async_call() await t._async_call()
assert str(e.value) == "TransportError(N/A, 'Unable to sniff hosts.')" assert str(e.value) == "TransportError(N/A, 'Unable to sniff hosts.')"
async def test_sniff_on_start_waits_for_sniff_to_complete(self, event_loop): async def test_sniff_on_start_waits_for_sniff_to_complete(
t = AsyncTransport( self, event_loop: Any
) -> None:
t: Any = AsyncTransport(
[ [
{"delay": 1, "data": ""}, {"delay": 1, "data": ""},
{"delay": 1, "data": ""}, {"delay": 1, "data": ""},
@@ -521,8 +531,10 @@ class TestTransport:
# and then resolved immediately after. # and then resolved immediately after.
assert 1 <= duration < 2 assert 1 <= duration < 2
async def test_sniff_on_start_close_unlocks_async_calls(self, event_loop): async def test_sniff_on_start_close_unlocks_async_calls(
t = AsyncTransport( self, event_loop: Any
) -> None:
t: Any = AsyncTransport(
[ [
{"delay": 10, "data": CLUSTER_NODES}, {"delay": 10, "data": CLUSTER_NODES},
], ],
@@ -559,7 +571,7 @@ class TestTransport:
""" """
amt_hosts = 4 amt_hosts = 4
hosts = [{"host": "localhost", "port": 9092}] * amt_hosts hosts = [{"host": "localhost", "port": 9092}] * amt_hosts
t = AsyncTransport( t: Any = AsyncTransport(
hosts=hosts, hosts=hosts,
) )
await t._async_init() await t._async_init()
@@ -577,7 +589,7 @@ class TestTransport:
""" """
amt_hosts = 4 amt_hosts = 4
hosts = [{"host": "localhost", "port": 9092}] * amt_hosts hosts = [{"host": "localhost", "port": 9092}] * amt_hosts
t = AsyncTransport( t: Any = AsyncTransport(
hosts=hosts, hosts=hosts,
connection_class=AIOHttpConnection, connection_class=AIOHttpConnection,
) )
+22 -10
View File
@@ -27,21 +27,30 @@
from collections import defaultdict from collections import defaultdict
from unittest import SkipTest # noqa: F401 from typing import Any, Sequence
from unittest import TestCase from unittest import SkipTest, TestCase
from opensearchpy import OpenSearch from opensearchpy import OpenSearch
class DummyTransport(object): class DummyTransport(object):
def __init__(self, hosts, responses=None, **kwargs) -> None: def __init__(
self, hosts: Sequence[str], responses: Any = None, **kwargs: Any
) -> None:
self.hosts = hosts self.hosts = hosts
self.responses = responses self.responses = responses
self.call_count = 0 self.call_count: int = 0
self.calls = defaultdict(list) self.calls: Any = defaultdict(list)
def perform_request(self, method, url, params=None, headers=None, body=None): def perform_request(
resp = 200, {} self,
method: str,
url: str,
params: Any = None,
headers: Any = None,
body: Any = None,
) -> Any:
resp: Any = (200, {})
if self.responses: if self.responses:
resp = self.responses[self.call_count] resp = self.responses[self.call_count]
self.call_count += 1 self.call_count += 1
@@ -52,12 +61,12 @@ class DummyTransport(object):
class OpenSearchTestCase(TestCase): class OpenSearchTestCase(TestCase):
def setUp(self) -> None: def setUp(self) -> None:
super(OpenSearchTestCase, self).setUp() super(OpenSearchTestCase, self).setUp()
self.client = OpenSearch(transport_class=DummyTransport) self.client: Any = OpenSearch(transport_class=DummyTransport) # type: ignore
def assert_call_count_equals(self, count) -> None: def assert_call_count_equals(self, count: int) -> None:
self.assertEqual(count, self.client.transport.call_count) self.assertEqual(count, self.client.transport.call_count)
def assert_url_called(self, method, url, count: int = 1): def assert_url_called(self, method: str, url: str, count: int = 1) -> Any:
self.assertIn((method, url), self.client.transport.calls) self.assertIn((method, url), self.client.transport.calls)
calls = self.client.transport.calls[(method, url)] calls = self.client.transport.calls[(method, url)]
self.assertEqual(count, len(calls)) self.assertEqual(count, len(calls))
@@ -78,3 +87,6 @@ class TestOpenSearchTestCase(OpenSearchTestCase):
self.assertEqual( self.assertEqual(
[({}, None, "body")], self.assert_url_called("DELETE", "/42", 1) [({}, None, "body")], self.assert_url_called("DELETE", "/42", 1)
) )
__all__ = ["SkipTest", "TestCase"]
@@ -17,7 +17,8 @@ class TestPluginsClient(TestCase):
def test_plugins_client(self) -> None: def test_plugins_client(self) -> None:
with self.assertWarns(Warning) as w: with self.assertWarns(Warning) as w:
client = OpenSearch() client = OpenSearch()
client.plugins.__init__(client) # double-init # double-init
client.plugins.__init__(client) # type: ignore
self.assertEqual( self.assertEqual(
str(w.warnings[0].message), str(w.warnings[0].message),
"Cannot load `alerting` directly to OpenSearch as it already exists. Use `OpenSearch.plugin.alerting` instead.", "Cannot load `alerting` directly to OpenSearch as it already exists. Use `OpenSearch.plugin.alerting` instead.",
+5 -3
View File
@@ -28,17 +28,19 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from typing import Any
from opensearchpy.client.utils import _bulk_body, _escape, _make_path, query_params from opensearchpy.client.utils import _bulk_body, _escape, _make_path, query_params
from ..test_cases import TestCase from ..test_cases import TestCase
class TestQueryParams(TestCase): class TestQueryParams(TestCase):
def setup_method(self, _) -> None: def setup_method(self, _: Any) -> None:
self.calls = [] self.calls: Any = []
@query_params("simple_param") @query_params("simple_param")
def func_to_wrap(self, *args, **kwargs) -> None: def func_to_wrap(self, *args: Any, **kwargs: Any) -> None:
self.calls.append((args, kwargs)) self.calls.append((args, kwargs))
def test_handles_params(self) -> None: def test_handles_params(self) -> None:
@@ -88,7 +88,7 @@ class TestBaseConnection(TestCase):
self.assertEqual([str(w.message) for w in warn], ["warning", "folded"]) self.assertEqual([str(w.message) for w in warn], ["warning", "folded"])
def test_ipv6_host_and_port(self): def test_ipv6_host_and_port(self) -> None:
for kwargs, expected_host in [ for kwargs, expected_host in [
({"host": "::1"}, "http://[::1]:9200"), ({"host": "::1"}, "http://[::1]:9200"),
({"host": "::1", "port": 443}, "http://[::1]:443"), ({"host": "::1", "port": 443}, "http://[::1]:443"),
@@ -96,7 +96,7 @@ class TestBaseConnection(TestCase):
({"host": "127.0.0.1", "port": 1234}, "http://127.0.0.1:1234"), ({"host": "127.0.0.1", "port": 1234}, "http://127.0.0.1:1234"),
({"host": "localhost", "use_ssl": True}, "https://localhost:9200"), ({"host": "localhost", "use_ssl": True}, "https://localhost:9200"),
]: ]:
conn = Connection(**kwargs) conn = Connection(**kwargs) # type: ignore
assert conn.host == expected_host assert conn.host == expected_host
def test_compatibility_accept_header(self) -> None: def test_compatibility_accept_header(self) -> None:
@@ -30,6 +30,7 @@ import json
import re import re
import uuid import uuid
import warnings import warnings
from typing import Any
import pytest import pytest
from mock import Mock, patch from mock import Mock, patch
@@ -49,24 +50,27 @@ from ..test_cases import TestCase
class TestRequestsHttpConnection(TestCase): class TestRequestsHttpConnection(TestCase):
def _get_mock_connection( def _get_mock_connection(
self, connection_params={}, status_code: int = 200, response_body: bytes = b"{}" self,
): connection_params: Any = {},
status_code: int = 200,
response_body: bytes = b"{}",
) -> Any:
con = RequestsHttpConnection(**connection_params) con = RequestsHttpConnection(**connection_params)
def _dummy_send(*args, **kwargs): def _dummy_send(*args: Any, **kwargs: Any) -> Any:
dummy_response = Mock() dummy_response = Mock()
dummy_response.headers = {} dummy_response.headers = {}
dummy_response.status_code = status_code dummy_response.status_code = status_code
dummy_response.content = response_body dummy_response.content = response_body
dummy_response.request = args[0] dummy_response.request = args[0]
dummy_response.cookies = {} dummy_response.cookies = {}
_dummy_send.call_args = (args, kwargs) _dummy_send.call_args = (args, kwargs) # type: ignore
return dummy_response return dummy_response
con.session.send = _dummy_send con.session.send = _dummy_send # type: ignore
return con return con
def _get_request(self, connection, *args, **kwargs): def _get_request(self, connection: Any, *args: Any, **kwargs: Any) -> Any:
if "body" in kwargs: if "body" in kwargs:
kwargs["body"] = kwargs["body"].encode("utf-8") kwargs["body"] = kwargs["body"].encode("utf-8")
@@ -237,14 +241,14 @@ class TestRequestsHttpConnection(TestCase):
self.assertRaises(RequestError, con.perform_request, "GET", "/", {}, "") self.assertRaises(RequestError, con.perform_request, "GET", "/", {}, "")
@patch("opensearchpy.connection.base.logger") @patch("opensearchpy.connection.base.logger")
def test_head_with_404_doesnt_get_logged(self, logger) -> None: def test_head_with_404_doesnt_get_logged(self, logger: Any) -> None:
con = self._get_mock_connection(status_code=404) con = self._get_mock_connection(status_code=404)
self.assertRaises(NotFoundError, con.perform_request, "HEAD", "/", {}, "") self.assertRaises(NotFoundError, con.perform_request, "HEAD", "/", {}, "")
self.assertEqual(0, logger.warning.call_count) self.assertEqual(0, logger.warning.call_count)
@patch("opensearchpy.connection.base.tracer") @patch("opensearchpy.connection.base.tracer")
@patch("opensearchpy.connection.base.logger") @patch("opensearchpy.connection.base.logger")
def test_failed_request_logs_and_traces(self, logger, tracer) -> None: def test_failed_request_logs_and_traces(self, logger: Any, tracer: Any) -> None:
con = self._get_mock_connection( con = self._get_mock_connection(
response_body=b'{"answer": 42}', status_code=500 response_body=b'{"answer": 42}', status_code=500
) )
@@ -272,7 +276,7 @@ class TestRequestsHttpConnection(TestCase):
@patch("opensearchpy.connection.base.tracer") @patch("opensearchpy.connection.base.tracer")
@patch("opensearchpy.connection.base.logger") @patch("opensearchpy.connection.base.logger")
def test_success_logs_and_traces(self, logger, tracer) -> None: def test_success_logs_and_traces(self, logger: Any, tracer: Any) -> None:
con = self._get_mock_connection(response_body=b"""{"answer": "that's it!"}""") con = self._get_mock_connection(response_body=b"""{"answer": "that's it!"}""")
status, headers, data = con.perform_request( status, headers, data = con.perform_request(
"GET", "GET",
@@ -311,7 +315,7 @@ class TestRequestsHttpConnection(TestCase):
self.assertEqual('< {"answer": "that\'s it!"}', resp[0][0] % resp[0][1:]) self.assertEqual('< {"answer": "that\'s it!"}', resp[0][0] % resp[0][1:])
@patch("opensearchpy.connection.base.logger") @patch("opensearchpy.connection.base.logger")
def test_uncompressed_body_logged(self, logger) -> None: def test_uncompressed_body_logged(self, logger: Any) -> None:
con = self._get_mock_connection(connection_params={"http_compress": True}) con = self._get_mock_connection(connection_params={"http_compress": True})
con.perform_request("GET", "/", body=b'{"example": "body"}') con.perform_request("GET", "/", body=b'{"example": "body"}')
@@ -366,7 +370,7 @@ class TestRequestsHttpConnection(TestCase):
self.assertEqual(request.headers["authorization"], "Basic dXNlcm5hbWU6c2VjcmV0") self.assertEqual(request.headers["authorization"], "Basic dXNlcm5hbWU6c2VjcmV0")
@patch("opensearchpy.connection.base.tracer") @patch("opensearchpy.connection.base.tracer")
def test_url_prefix(self, tracer) -> None: def test_url_prefix(self, tracer: Any) -> None:
con = self._get_mock_connection({"url_prefix": "/some-prefix/"}) con = self._get_mock_connection({"url_prefix": "/some-prefix/"})
request = self._get_request( request = self._get_request(
con, "GET", "/_search", body='{"answer": 42}', timeout=0.1 con, "GET", "/_search", body='{"answer": 42}', timeout=0.1
@@ -392,16 +396,16 @@ class TestRequestsHttpConnection(TestCase):
def test_recursion_error_reraised(self) -> None: def test_recursion_error_reraised(self) -> None:
conn = RequestsHttpConnection() conn = RequestsHttpConnection()
def send_raise(*_, **__): def send_raise(*_: Any, **__: Any) -> Any:
raise RecursionError("Wasn't modified!") raise RecursionError("Wasn't modified!")
conn.session.send = send_raise conn.session.send = send_raise # type: ignore
with pytest.raises(RecursionError) as e: with pytest.raises(RecursionError) as e:
conn.perform_request("GET", "/") conn.perform_request("GET", "/")
assert str(e.value) == "Wasn't modified!" assert str(e.value) == "Wasn't modified!"
def mock_session(self): def mock_session(self) -> Any:
access_key = uuid.uuid4().hex access_key = uuid.uuid4().hex
secret_key = uuid.uuid4().hex secret_key = uuid.uuid4().hex
token = uuid.uuid4().hex token = uuid.uuid4().hex
@@ -448,7 +452,7 @@ class TestRequestsHttpConnection(TestCase):
self.assertIn("X-Amz-Security-Token", prepared_request.headers) self.assertIn("X-Amz-Security-Token", prepared_request.headers)
@patch("opensearchpy.helpers.signer.AWSV4Signer.sign") @patch("opensearchpy.helpers.signer.AWSV4Signer.sign")
def test_aws_signer_signs_with_query_string(self, mock_sign) -> None: def test_aws_signer_signs_with_query_string(self, mock_sign: Any) -> None:
region = "us-west-1" region = "us-west-1"
service = "aoss" service = "aoss"
@@ -469,6 +473,9 @@ class TestRequestsHttpConnection(TestCase):
class TestRequestsConnectionRedirect: class TestRequestsConnectionRedirect:
server1: TestHTTPServer
server2: TestHTTPServer
@classmethod @classmethod
def setup_class(cls) -> None: def setup_class(cls) -> None:
# Start servers # Start servers
@@ -505,7 +512,7 @@ class TestRequestsConnectionRedirect:
class TestSignerWithFrozenCredentials(TestRequestsHttpConnection): class TestSignerWithFrozenCredentials(TestRequestsHttpConnection):
def mock_session(self): def mock_session(self) -> Any:
access_key = uuid.uuid4().hex access_key = uuid.uuid4().hex
secret_key = uuid.uuid4().hex secret_key = uuid.uuid4().hex
token = uuid.uuid4().hex token = uuid.uuid4().hex
@@ -32,6 +32,7 @@ import warnings
from gzip import GzipFile from gzip import GzipFile
from io import BytesIO from io import BytesIO
from platform import python_version from platform import python_version
from typing import Any
import pytest import pytest
import urllib3 import urllib3
@@ -45,15 +46,17 @@ from ..test_cases import SkipTest, TestCase
class TestUrllib3HttpConnection(TestCase): class TestUrllib3HttpConnection(TestCase):
def _get_mock_connection(self, connection_params={}, response_body: bytes = b"{}"): def _get_mock_connection(
self, connection_params: Any = {}, response_body: bytes = b"{}"
) -> Any:
con = Urllib3HttpConnection(**connection_params) con = Urllib3HttpConnection(**connection_params)
def _dummy_urlopen(*args, **kwargs): def _dummy_urlopen(*args: Any, **kwargs: Any) -> Any:
dummy_response = Mock() dummy_response = Mock()
dummy_response.headers = HTTPHeaderDict({}) dummy_response.headers = HTTPHeaderDict({})
dummy_response.status = 200 dummy_response.status = 200
dummy_response.data = response_body dummy_response.data = response_body
_dummy_urlopen.call_args = (args, kwargs) _dummy_urlopen.call_args = (args, kwargs) # type: ignore
return dummy_response return dummy_response
con.pool.urlopen = _dummy_urlopen con.pool.urlopen = _dummy_urlopen
@@ -181,7 +184,7 @@ class TestUrllib3HttpConnection(TestCase):
"urllib3.HTTPConnectionPool.urlopen", "urllib3.HTTPConnectionPool.urlopen",
return_value=Mock(status=200, headers=HTTPHeaderDict({}), data=b"{}"), return_value=Mock(status=200, headers=HTTPHeaderDict({}), data=b"{}"),
) )
def test_aws_signer_as_http_auth_adds_headers(self, mock_open) -> None: def test_aws_signer_as_http_auth_adds_headers(self, mock_open: Any) -> None:
from opensearchpy.helpers.signer import Urllib3AWSV4SignerAuth from opensearchpy.helpers.signer import Urllib3AWSV4SignerAuth
auth = Urllib3AWSV4SignerAuth(self.mock_session(), "us-west-2") auth = Urllib3AWSV4SignerAuth(self.mock_session(), "us-west-2")
@@ -247,7 +250,7 @@ class TestUrllib3HttpConnection(TestCase):
self.assertIn("X-Amz-Date", headers) self.assertIn("X-Amz-Date", headers)
self.assertIn("X-Amz-Security-Token", headers) self.assertIn("X-Amz-Security-Token", headers)
def mock_session(self): def mock_session(self) -> Any:
access_key = uuid.uuid4().hex access_key = uuid.uuid4().hex
secret_key = uuid.uuid4().hex secret_key = uuid.uuid4().hex
token = uuid.uuid4().hex token = uuid.uuid4().hex
@@ -290,6 +293,7 @@ class TestUrllib3HttpConnection(TestCase):
self.assertEqual(0, len(w)) self.assertEqual(0, len(w))
def test_warns_if_using_non_default_ssl_kwargs_with_ssl_context(self) -> None: def test_warns_if_using_non_default_ssl_kwargs_with_ssl_context(self) -> None:
kwargs: Any
for kwargs in ( for kwargs in (
{"ssl_show_warn": False}, {"ssl_show_warn": False},
{"ssl_show_warn": True}, {"ssl_show_warn": True},
@@ -325,7 +329,7 @@ class TestUrllib3HttpConnection(TestCase):
self.assertIsNone(c.pool.ca_certs) self.assertIsNone(c.pool.ca_certs)
@patch("opensearchpy.connection.base.logger") @patch("opensearchpy.connection.base.logger")
def test_uncompressed_body_logged(self, logger) -> None: def test_uncompressed_body_logged(self, logger: Any) -> None:
con = self._get_mock_connection(connection_params={"http_compress": True}) con = self._get_mock_connection(connection_params={"http_compress": True})
con.perform_request("GET", "/", body=b'{"example": "body"}') con.perform_request("GET", "/", body=b'{"example": "body"}')
@@ -344,7 +348,7 @@ class TestUrllib3HttpConnection(TestCase):
def test_recursion_error_reraised(self) -> None: def test_recursion_error_reraised(self) -> None:
conn = Urllib3HttpConnection() conn = Urllib3HttpConnection()
def urlopen_raise(*_, **__): def urlopen_raise(*_: Any, **__: Any) -> Any:
raise RecursionError("Wasn't modified!") raise RecursionError("Wasn't modified!")
conn.pool.urlopen = urlopen_raise conn.pool.urlopen = urlopen_raise
@@ -355,7 +359,7 @@ class TestUrllib3HttpConnection(TestCase):
class TestSignerWithFrozenCredentials(TestUrllib3HttpConnection): class TestSignerWithFrozenCredentials(TestUrllib3HttpConnection):
def mock_session(self): def mock_session(self) -> Any:
access_key = uuid.uuid4().hex access_key = uuid.uuid4().hex
secret_key = uuid.uuid4().hex secret_key = uuid.uuid4().hex
token = uuid.uuid4().hex token = uuid.uuid4().hex
+4 -3
View File
@@ -27,6 +27,7 @@
import time import time
from typing import Any
from opensearchpy.connection import Connection from opensearchpy.connection import Connection
from opensearchpy.connection_pool import ( from opensearchpy.connection_pool import (
@@ -57,7 +58,7 @@ class TestConnectionPool(TestCase):
connections.add(pool.get_connection()) connections.add(pool.get_connection())
self.assertEqual(connections, set(range(100))) self.assertEqual(connections, set(range(100)))
def test_disable_shuffling(self): def test_disable_shuffling(self) -> None:
pool = ConnectionPool([(x, {}) for x in range(100)], randomize_hosts=False) pool = ConnectionPool([(x, {}) for x in range(100)], randomize_hosts=False)
connections = [] connections = []
@@ -65,9 +66,9 @@ class TestConnectionPool(TestCase):
connections.append(pool.get_connection()) connections.append(pool.get_connection())
self.assertEqual(connections, list(range(100))) self.assertEqual(connections, list(range(100)))
def test_selectors_have_access_to_connection_opts(self): def test_selectors_have_access_to_connection_opts(self) -> None:
class MySelector(RoundRobinSelector): class MySelector(RoundRobinSelector):
def select(self, connections): def select(self, connections: Any) -> Any:
return self.connection_opts[ return self.connection_opts[
super(MySelector, self).select(connections) super(MySelector, self).select(connections)
]["actual"] ]["actual"]
+11 -9
View File
@@ -26,24 +26,26 @@
# under the License. # under the License.
from typing import Any
from mock import Mock from mock import Mock
from pytest import fixture from pytest import fixture
from opensearchpy.connection.connections import add_connection, connections from opensearchpy.connection.connections import add_connection, connections
@fixture @fixture # type: ignore
def mock_client(dummy_response): def mock_client(dummy_response: Any) -> Any:
client = Mock() client = Mock()
client.search.return_value = dummy_response client.search.return_value = dummy_response
add_connection("mock", client) add_connection("mock", client)
yield client yield client
connections._conn = {} connections._conns = {}
connections._kwargs = {} connections._kwargs = {}
@fixture @fixture # type: ignore
def dummy_response(): def dummy_response() -> Any:
return { return {
"_shards": {"failed": 0, "successful": 10, "total": 10}, "_shards": {"failed": 0, "successful": 10, "total": 10},
"hits": { "hits": {
@@ -91,8 +93,8 @@ def dummy_response():
} }
@fixture @fixture # type: ignore
def aggs_search(): def aggs_search() -> Any:
from opensearchpy import Search from opensearchpy import Search
s = Search(index="flat-git") s = Search(index="flat-git")
@@ -106,8 +108,8 @@ def aggs_search():
return s return s
@fixture @fixture # type: ignore
def aggs_data(): def aggs_data() -> Any:
return { return {
"took": 4, "took": 4,
"timed_out": False, "timed_out": False,
+13 -12
View File
@@ -28,6 +28,7 @@
import threading import threading
import time import time
from typing import Any
import mock import mock
import pytest import pytest
@@ -40,19 +41,19 @@ from ..test_cases import TestCase
lock_side_effect = threading.Lock() lock_side_effect = threading.Lock()
def mock_process_bulk_chunk(*args, **kwargs): def mock_process_bulk_chunk(*args: Any, **kwargs: Any) -> Any:
""" """
Threadsafe way of mocking process bulk chunk: Threadsafe way of mocking process bulk chunk:
https://stackoverflow.com/questions/39332139/thread-safe-version-of-mock-call-count https://stackoverflow.com/questions/39332139/thread-safe-version-of-mock-call-count
""" """
with lock_side_effect: with lock_side_effect:
mock_process_bulk_chunk.call_count += 1 mock_process_bulk_chunk.call_count += 1 # type: ignore
time.sleep(0.1) time.sleep(0.1)
return [] return []
mock_process_bulk_chunk.call_count = 0 mock_process_bulk_chunk.call_count = 0 # type: ignore
class TestParallelBulk(TestCase): class TestParallelBulk(TestCase):
@@ -60,21 +61,21 @@ class TestParallelBulk(TestCase):
"opensearchpy.helpers.actions._process_bulk_chunk", "opensearchpy.helpers.actions._process_bulk_chunk",
side_effect=mock_process_bulk_chunk, side_effect=mock_process_bulk_chunk,
) )
def test_all_chunks_sent(self, _process_bulk_chunk) -> None: def test_all_chunks_sent(self, _process_bulk_chunk: Any) -> None:
actions = ({"x": i} for i in range(100)) actions = ({"x": i} for i in range(100))
list(helpers.parallel_bulk(OpenSearch(), actions, chunk_size=2)) list(helpers.parallel_bulk(OpenSearch(), actions, chunk_size=2))
self.assertEqual(50, mock_process_bulk_chunk.call_count) self.assertEqual(50, mock_process_bulk_chunk.call_count) # type: ignore
@pytest.mark.skip @pytest.mark.skip # type: ignore
@mock.patch( @mock.patch(
"opensearchpy.helpers.actions._process_bulk_chunk", "opensearchpy.helpers.actions._process_bulk_chunk",
# make sure we spend some time in the thread # make sure we spend some time in the thread
side_effect=lambda *a: [ side_effect=lambda *a: [
(True, time.sleep(0.001) or threading.current_thread().ident) (True, time.sleep(0.001) or threading.current_thread().ident) # type: ignore
], ],
) )
def test_chunk_sent_from_different_threads(self, _process_bulk_chunk) -> None: def test_chunk_sent_from_different_threads(self, _process_bulk_chunk: Any) -> None:
actions = ({"x": i} for i in range(100)) actions = ({"x": i} for i in range(100))
results = list( results = list(
helpers.parallel_bulk(OpenSearch(), actions, thread_count=10, chunk_size=2) helpers.parallel_bulk(OpenSearch(), actions, thread_count=10, chunk_size=2)
@@ -83,8 +84,8 @@ class TestParallelBulk(TestCase):
class TestChunkActions(TestCase): class TestChunkActions(TestCase):
def setup_method(self, _) -> None: def setup_method(self, _: Any) -> None:
self.actions = [({"index": {}}, {"some": u"datá", "i": i}) for i in range(100)] # fmt: skip self.actions: Any = [({"index": {}}, {"some": u"datá", "i": i}) for i in range(100)] # fmt: skip
def test_expand_action(self) -> None: def test_expand_action(self) -> None:
self.assertEqual(helpers.expand_action({}), ({"index": {}}, {})) self.assertEqual(helpers.expand_action({}), ({"index": {}}, {}))
@@ -92,7 +93,7 @@ class TestChunkActions(TestCase):
helpers.expand_action({"key": "val"}), ({"index": {}}, {"key": "val"}) helpers.expand_action({"key": "val"}), ({"index": {}}, {"key": "val"})
) )
def test_expand_action_actions(self): def test_expand_action_actions(self) -> None:
self.assertEqual( self.assertEqual(
helpers.expand_action( helpers.expand_action(
{"_op_type": "delete", "_id": "id", "_index": "index"} {"_op_type": "delete", "_id": "id", "_index": "index"}
@@ -154,7 +155,7 @@ class TestChunkActions(TestCase):
({"index": {action_option: 0}}, {"key": "val"}), ({"index": {action_option: 0}}, {"key": "val"}),
) )
def test__source_metadata_or_source(self): def test__source_metadata_or_source(self) -> None:
self.assertEqual( self.assertEqual(
helpers.expand_action({"_source": {"key": "val"}}), helpers.expand_action({"_source": {"key": "val"}}),
({"index": {}}, {"key": "val"}), ({"index": {}}, {"key": "val"}),
+13 -13
View File
@@ -37,7 +37,7 @@ def test_repr() -> None:
assert "Terms(aggs={'max_score': Max(field='score')}, field='tags')" == repr(a) assert "Terms(aggs={'max_score': Max(field='score')}, field='tags')" == repr(a)
def test_meta(): def test_meta() -> None:
max_score = aggs.Max(field="score") max_score = aggs.Max(field="score")
a = aggs.A( a = aggs.A(
"terms", field="tags", aggs={"max_score": max_score}, meta={"some": "metadata"} "terms", field="tags", aggs={"max_score": max_score}, meta={"some": "metadata"}
@@ -66,7 +66,7 @@ def test_A_creates_proper_agg() -> None:
assert a._params == {"field": "tags"} assert a._params == {"field": "tags"}
def test_A_handles_nested_aggs_properly(): def test_A_handles_nested_aggs_properly() -> None:
max_score = aggs.Max(field="score") max_score = aggs.Max(field="score")
a = aggs.A("terms", field="tags", aggs={"max_score": max_score}) a = aggs.A("terms", field="tags", aggs={"max_score": max_score})
@@ -79,7 +79,7 @@ def test_A_passes_aggs_through() -> None:
assert aggs.A(a) is a assert aggs.A(a) is a
def test_A_from_dict(): def test_A_from_dict() -> None:
d = { d = {
"terms": {"field": "tags"}, "terms": {"field": "tags"},
"aggs": {"per_author": {"terms": {"field": "author.raw"}}}, "aggs": {"per_author": {"terms": {"field": "author.raw"}}},
@@ -95,7 +95,7 @@ def test_A_from_dict():
assert a.aggs.per_author == aggs.A("terms", field="author.raw") assert a.aggs.per_author == aggs.A("terms", field="author.raw")
def test_A_fails_with_incorrect_dict(): def test_A_fails_with_incorrect_dict() -> None:
correct_d = { correct_d = {
"terms": {"field": "tags"}, "terms": {"field": "tags"},
"aggs": {"per_author": {"terms": {"field": "author.raw"}}}, "aggs": {"per_author": {"terms": {"field": "author.raw"}}},
@@ -148,7 +148,7 @@ def test_buckets_equals_counts_subaggs() -> None:
assert a != b assert a != b
def test_buckets_to_dict(): def test_buckets_to_dict() -> None:
a = aggs.Terms(field="tags") a = aggs.Terms(field="tags")
a.bucket("per_author", "terms", field="author.raw") a.bucket("per_author", "terms", field="author.raw")
@@ -189,7 +189,7 @@ def test_filter_can_be_instantiated_using_positional_args() -> None:
assert a == aggs.A("filter", query.Q("term", f=42)) assert a == aggs.A("filter", query.Q("term", f=42))
def test_filter_aggregation_as_nested_agg(): def test_filter_aggregation_as_nested_agg() -> None:
a = aggs.Terms(field="tags") a = aggs.Terms(field="tags")
a.bucket("filtered", "filter", query.Q("term", f=42)) a.bucket("filtered", "filter", query.Q("term", f=42))
@@ -199,7 +199,7 @@ def test_filter_aggregation_as_nested_agg():
} == a.to_dict() } == a.to_dict()
def test_filter_aggregation_with_nested_aggs(): def test_filter_aggregation_with_nested_aggs() -> None:
a = aggs.Filter(query.Q("term", f=42)) a = aggs.Filter(query.Q("term", f=42))
a.bucket("testing", "terms", field="tags") a.bucket("testing", "terms", field="tags")
@@ -229,7 +229,7 @@ def test_filters_correctly_identifies_the_hash() -> None:
assert a.filters.group_a == query.Q("term", group="a") assert a.filters.group_a == query.Q("term", group="a")
def test_bucket_sort_agg(): def test_bucket_sort_agg() -> None:
bucket_sort_agg = aggs.BucketSort(sort=[{"total_sales": {"order": "desc"}}], size=3) bucket_sort_agg = aggs.BucketSort(sort=[{"total_sales": {"order": "desc"}}], size=3)
assert bucket_sort_agg.to_dict() == { assert bucket_sort_agg.to_dict() == {
"bucket_sort": {"sort": [{"total_sales": {"order": "desc"}}], "size": 3} "bucket_sort": {"sort": [{"total_sales": {"order": "desc"}}], "size": 3}
@@ -254,7 +254,7 @@ def test_bucket_sort_agg():
} == a.to_dict() } == a.to_dict()
def test_bucket_sort_agg_only_trnunc(): def test_bucket_sort_agg_only_trnunc() -> None:
bucket_sort_agg = aggs.BucketSort(**{"from": 1, "size": 1}) bucket_sort_agg = aggs.BucketSort(**{"from": 1, "size": 1})
assert bucket_sort_agg.to_dict() == {"bucket_sort": {"from": 1, "size": 1}} assert bucket_sort_agg.to_dict() == {"bucket_sort": {"from": 1, "size": 1}}
@@ -284,7 +284,7 @@ def test_boxplot_aggregation() -> None:
assert {"boxplot": {"field": "load_time"}} == a.to_dict() assert {"boxplot": {"field": "load_time"}} == a.to_dict()
def test_rare_terms_aggregation(): def test_rare_terms_aggregation() -> None:
a = aggs.RareTerms(field="the-field") a = aggs.RareTerms(field="the-field")
a.bucket("total_sales", "sum", field="price") a.bucket("total_sales", "sum", field="price")
a.bucket( a.bucket(
@@ -316,7 +316,7 @@ def test_median_absolute_deviation_aggregation() -> None:
assert {"median_absolute_deviation": {"field": "rating"}} == a.to_dict() assert {"median_absolute_deviation": {"field": "rating"}} == a.to_dict()
def test_t_test_aggregation(): def test_t_test_aggregation() -> None:
a = aggs.TTest( a = aggs.TTest(
a={"field": "startup_time_before"}, a={"field": "startup_time_before"},
b={"field": "startup_time_after"}, b={"field": "startup_time_after"},
@@ -332,14 +332,14 @@ def test_t_test_aggregation():
} == a.to_dict() } == a.to_dict()
def test_inference_aggregation(): def test_inference_aggregation() -> None:
a = aggs.Inference(model_id="model-id", buckets_path={"agg_name": "agg_name"}) a = aggs.Inference(model_id="model-id", buckets_path={"agg_name": "agg_name"})
assert { assert {
"inference": {"buckets_path": {"agg_name": "agg_name"}, "model_id": "model-id"} "inference": {"buckets_path": {"agg_name": "agg_name"}, "model_id": "model-id"}
} == a.to_dict() } == a.to_dict()
def test_moving_percentiles_aggregation(): def test_moving_percentiles_aggregation() -> None:
a = aggs.DateHistogram() a = aggs.DateHistogram()
a.bucket("the_percentile", "percentiles", field="price", percents=[1.0, 99.0]) a.bucket("the_percentile", "percentiles", field="price", percents=[1.0, 99.0])
a.pipeline( a.pipeline(
@@ -36,7 +36,7 @@ def test_analyzer_serializes_as_name() -> None:
assert "my_analyzer" == a.to_dict() assert "my_analyzer" == a.to_dict()
def test_analyzer_has_definition(): def test_analyzer_has_definition() -> None:
a = analysis.CustomAnalyzer( a = analysis.CustomAnalyzer(
"my_analyzer", tokenizer="keyword", filter=["lowercase"] "my_analyzer", tokenizer="keyword", filter=["lowercase"]
) )
@@ -48,7 +48,7 @@ def test_analyzer_has_definition():
} == a.get_definition() } == a.get_definition()
def test_simple_multiplexer_filter(): def test_simple_multiplexer_filter() -> None:
a = analysis.analyzer( a = analysis.analyzer(
"my_analyzer", "my_analyzer",
tokenizer="keyword", tokenizer="keyword",
@@ -76,7 +76,7 @@ def test_simple_multiplexer_filter():
} == a.get_analysis_definition() } == a.get_analysis_definition()
def test_multiplexer_with_custom_filter(): def test_multiplexer_with_custom_filter() -> None:
a = analysis.analyzer( a = analysis.analyzer(
"my_analyzer", "my_analyzer",
tokenizer="keyword", tokenizer="keyword",
@@ -107,7 +107,7 @@ def test_multiplexer_with_custom_filter():
} == a.get_analysis_definition() } == a.get_analysis_definition()
def test_conditional_token_filter(): def test_conditional_token_filter() -> None:
a = analysis.analyzer( a = analysis.analyzer(
"my_cond", "my_cond",
tokenizer=analysis.tokenizer("keyword"), tokenizer=analysis.tokenizer("keyword"),
@@ -172,7 +172,7 @@ def test_normalizer_serializes_as_name() -> None:
assert "my_normalizer" == n.to_dict() assert "my_normalizer" == n.to_dict()
def test_normalizer_has_definition(): def test_normalizer_has_definition() -> None:
n = analysis.CustomNormalizer( n = analysis.CustomNormalizer(
"my_normalizer", filter=["lowercase", "asciifolding"], char_filter=["quote"] "my_normalizer", filter=["lowercase", "asciifolding"], char_filter=["quote"]
) )
@@ -191,7 +191,7 @@ def test_tokenizer() -> None:
assert {"type": "nGram", "min_gram": 3, "max_gram": 3} == t.get_definition() assert {"type": "nGram", "min_gram": 3, "max_gram": 3} == t.get_definition()
def test_custom_analyzer_can_collect_custom_items(): def test_custom_analyzer_can_collect_custom_items() -> None:
trigram = analysis.tokenizer("trigram", "nGram", min_gram=3, max_gram=3) trigram = analysis.tokenizer("trigram", "nGram", min_gram=3, max_gram=3)
my_stop = analysis.token_filter("my_stop", "stop", stopwords=["a", "b"]) my_stop = analysis.token_filter("my_stop", "stop", stopwords=["a", "b"])
umlauts = analysis.char_filter("umlauts", "pattern_replace", mappings=["ü=>ue"]) umlauts = analysis.char_filter("umlauts", "pattern_replace", mappings=["ü=>ue"])
+76 -67
View File
@@ -32,6 +32,7 @@ import ipaddress
import pickle import pickle
from datetime import datetime from datetime import datetime
from hashlib import sha256 from hashlib import sha256
from typing import Any
from pytest import raises from pytest import raises
@@ -52,7 +53,7 @@ class MyDoc(document.Document):
class MySubDoc(MyDoc): class MySubDoc(MyDoc):
name = field.Keyword() name: Any = field.Keyword()
class Index: class Index:
name = "default-index" name = "default-index"
@@ -92,10 +93,10 @@ class Secret(str):
class SecretField(field.CustomField): class SecretField(field.CustomField):
builtin_type = "text" builtin_type = "text"
def _serialize(self, data): def _serialize(self, data: Any) -> Any:
return codecs.encode(data, "rot_13") return codecs.encode(data, "rot_13")
def _deserialize(self, data): def _deserialize(self, data: Any) -> Any:
if isinstance(data, Secret): if isinstance(data, Secret):
return data return data
return Secret(codecs.decode(data, "rot_13")) return Secret(codecs.decode(data, "rot_13"))
@@ -114,6 +115,8 @@ class NestedSecret(document.Document):
class Index: class Index:
name = "test-nested-secret" name = "test-nested-secret"
_index: Any
class OptionalObjectWithRequiredField(document.Document): class OptionalObjectWithRequiredField(document.Document):
comments = field.Nested(properties={"title": field.Keyword(required=True)}) comments = field.Nested(properties={"title": field.Keyword(required=True)})
@@ -121,6 +124,8 @@ class OptionalObjectWithRequiredField(document.Document):
class Index: class Index:
name = "test-required" name = "test-required"
_index: Any
class Host(document.Document): class Host(document.Document):
ip = field.Ip() ip = field.Ip()
@@ -128,12 +133,14 @@ class Host(document.Document):
class Index: class Index:
name = "test-host" name = "test-host"
_index: Any
def test_range_serializes_properly() -> None: def test_range_serializes_properly() -> None:
class D(document.Document): class D(document.Document):
lr = field.LongRange() lr = field.LongRange()
d = D(lr=Range(lt=42)) d: Any = D(lr=Range(lt=42))
assert 40 in d.lr assert 40 in d.lr
assert 47 not in d.lr assert 47 not in d.lr
assert {"lr": {"lt": 42}} == d.to_dict() assert {"lr": {"lt": 42}} == d.to_dict()
@@ -146,7 +153,7 @@ def test_range_deserializes_properly() -> None:
class D(document.InnerDoc): class D(document.InnerDoc):
lr = field.LongRange() lr = field.LongRange()
d = D.from_opensearch({"lr": {"lt": 42}}, True) d: Any = D.from_opensearch({"lr": {"lt": 42}}, True)
assert isinstance(d.lr, Range) assert isinstance(d.lr, Range)
assert 40 in d.lr assert 40 in d.lr
assert 47 not in d.lr assert 47 not in d.lr
@@ -165,7 +172,7 @@ def test_conflicting_mapping_raises_error_in_index_to_dict() -> None:
class B(document.Document): class B(document.Document):
name = field.Keyword() name = field.Keyword()
i = Index("i") i: Any = Index("i")
i.document(A) i.document(A)
i.document(B) i.document(B)
@@ -174,7 +181,7 @@ def test_conflicting_mapping_raises_error_in_index_to_dict() -> None:
def test_ip_address_serializes_properly() -> None: def test_ip_address_serializes_properly() -> None:
host = Host(ip=ipaddress.IPv4Address("10.0.0.1")) host: Any = Host(ip=ipaddress.IPv4Address("10.0.0.1"))
assert {"ip": "10.0.0.1"} == host.to_dict() assert {"ip": "10.0.0.1"} == host.to_dict()
@@ -202,7 +209,7 @@ def test_matches_accepts_wildcards() -> None:
def test_assigning_attrlist_to_field() -> None: def test_assigning_attrlist_to_field() -> None:
sc = SimpleCommit() sc: Any = SimpleCommit()
ls = ["README", "README.rst"] ls = ["README", "README.rst"]
sc.files = utils.AttrList(ls) sc.files = utils.AttrList(ls)
@@ -210,20 +217,20 @@ def test_assigning_attrlist_to_field() -> None:
def test_optional_inner_objects_are_not_validated_if_missing() -> None: def test_optional_inner_objects_are_not_validated_if_missing() -> None:
d = OptionalObjectWithRequiredField() d: Any = OptionalObjectWithRequiredField()
assert d.full_clean() is None assert d.full_clean() is None
def test_custom_field() -> None: def test_custom_field() -> None:
s = SecretDoc(title=Secret("Hello")) s1: Any = SecretDoc(title=Secret("Hello"))
assert {"title": "Uryyb"} == s.to_dict() assert {"title": "Uryyb"} == s1.to_dict()
assert s.title == "Hello" assert s1.title == "Hello"
s = SecretDoc.from_opensearch({"_source": {"title": "Uryyb"}}) s2: Any = SecretDoc.from_opensearch({"_source": {"title": "Uryyb"}})
assert s.title == "Hello" assert s2.title == "Hello"
assert isinstance(s.title, Secret) assert isinstance(s2.title, Secret)
def test_custom_field_mapping() -> None: def test_custom_field_mapping() -> None:
@@ -233,7 +240,7 @@ def test_custom_field_mapping() -> None:
def test_custom_field_in_nested() -> None: def test_custom_field_in_nested() -> None:
s = NestedSecret() s: Any = NestedSecret()
s.secrets.append(SecretDoc(title=Secret("Hello"))) s.secrets.append(SecretDoc(title=Secret("Hello")))
assert {"secrets": [{"title": "Uryyb"}]} == s.to_dict() assert {"secrets": [{"title": "Uryyb"}]} == s.to_dict()
@@ -241,7 +248,7 @@ def test_custom_field_in_nested() -> None:
def test_multi_works_after_doc_has_been_saved() -> None: def test_multi_works_after_doc_has_been_saved() -> None:
c = SimpleCommit() c: Any = SimpleCommit()
c.full_clean() c.full_clean()
c.files.append("setup.py") c.files.append("setup.py")
@@ -250,7 +257,7 @@ def test_multi_works_after_doc_has_been_saved() -> None:
def test_multi_works_in_nested_after_doc_has_been_serialized() -> None: def test_multi_works_in_nested_after_doc_has_been_serialized() -> None:
# Issue #359 # Issue #359
c = DocWithNested(comments=[Comment(title="First!")]) c: Any = DocWithNested(comments=[Comment(title="First!")])
assert [] == c.comments[0].tags assert [] == c.comments[0].tags
assert {"comments": [{"title": "First!"}]} == c.to_dict() assert {"comments": [{"title": "First!"}]} == c.to_dict()
@@ -258,17 +265,19 @@ def test_multi_works_in_nested_after_doc_has_been_serialized() -> None:
def test_null_value_for_object() -> None: def test_null_value_for_object() -> None:
d = MyDoc(inner=None) d: Any = MyDoc(inner=None)
assert d.inner is None assert d.inner is None
def test_inherited_doc_types_can_override_index(): def test_inherited_doc_types_can_override_index() -> None:
class MyDocDifferentIndex(MySubDoc): class MyDocDifferentIndex(MySubDoc):
_index: Any
class Index: class Index:
name = "not-default-index" name = "not-default-index"
settings = {"number_of_replicas": 0} settings = {"number_of_replicas": 0}
aliases = {"a": {}} aliases: Any = {"a": {}}
analyzers = [analyzer("my_analizer", tokenizer="keyword")] analyzers = [analyzer("my_analizer", tokenizer="keyword")]
assert MyDocDifferentIndex._index._name == "not-default-index" assert MyDocDifferentIndex._index._name == "not-default-index"
@@ -295,8 +304,8 @@ def test_inherited_doc_types_can_override_index():
} }
def test_to_dict_with_meta(): def test_to_dict_with_meta() -> None:
d = MySubDoc(title="hello") d: Any = MySubDoc(title="hello")
d.meta.routing = "some-parent" d.meta.routing = "some-parent"
assert { assert {
@@ -306,29 +315,29 @@ def test_to_dict_with_meta():
} == d.to_dict(True) } == d.to_dict(True)
def test_to_dict_with_meta_includes_custom_index(): def test_to_dict_with_meta_includes_custom_index() -> None:
d = MySubDoc(title="hello") d: Any = MySubDoc(title="hello")
d.meta.index = "other-index" d.meta.index = "other-index"
assert {"_index": "other-index", "_source": {"title": "hello"}} == d.to_dict(True) assert {"_index": "other-index", "_source": {"title": "hello"}} == d.to_dict(True)
def test_to_dict_without_skip_empty_will_include_empty_fields() -> None: def test_to_dict_without_skip_empty_will_include_empty_fields() -> None:
d = MySubDoc(tags=[], title=None, inner={}) d: Any = MySubDoc(tags=[], title=None, inner={})
assert {} == d.to_dict() assert {} == d.to_dict()
assert {"tags": [], "title": None, "inner": {}} == d.to_dict(skip_empty=False) assert {"tags": [], "title": None, "inner": {}} == d.to_dict(skip_empty=False)
def test_attribute_can_be_removed() -> None: def test_attribute_can_be_removed() -> None:
d = MyDoc(title="hello") d: Any = MyDoc(title="hello")
del d.title del d.title
assert "title" not in d._d_ assert "title" not in d._d_
def test_doc_type_can_be_correctly_pickled() -> None: def test_doc_type_can_be_correctly_pickled() -> None:
d = DocWithNested( d: Any = DocWithNested(
title="Hello World!", comments=[Comment(title="hellp")], meta={"id": 42} title="Hello World!", comments=[Comment(title="hellp")], meta={"id": 42}
) )
s = pickle.dumps(d) s = pickle.dumps(d)
@@ -343,14 +352,14 @@ def test_doc_type_can_be_correctly_pickled() -> None:
def test_meta_is_accessible_even_on_empty_doc() -> None: def test_meta_is_accessible_even_on_empty_doc() -> None:
d = MyDoc() d1: Any = MyDoc()
d.meta d1.meta
d = MyDoc(title="aaa") d2: Any = MyDoc(title="aaa")
d.meta d2.meta
def test_meta_field_mapping(): def test_meta_field_mapping() -> None:
class User(document.Document): class User(document.Document):
username = field.Text() username = field.Text()
@@ -373,7 +382,7 @@ def test_multi_value_fields() -> None:
class Blog(document.Document): class Blog(document.Document):
tags = field.Keyword(multi=True) tags = field.Keyword(multi=True)
b = Blog() b: Any = Blog()
assert [] == b.tags assert [] == b.tags
b.tags.append("search") b.tags.append("search")
b.tags.append("python") b.tags.append("python")
@@ -382,20 +391,20 @@ def test_multi_value_fields() -> None:
def test_docs_with_properties() -> None: def test_docs_with_properties() -> None:
class User(document.Document): class User(document.Document):
pwd_hash = field.Text() pwd_hash: Any = field.Text()
def check_password(self, pwd): def check_password(self, pwd: Any) -> Any:
return sha256(pwd).hexdigest() == self.pwd_hash return sha256(pwd).hexdigest() == self.pwd_hash
@property @property
def password(self): def password(self) -> Any:
raise AttributeError("readonly") raise AttributeError("readonly")
@password.setter @password.setter
def password(self, pwd): def password(self, pwd: Any) -> None:
self.pwd_hash = sha256(pwd).hexdigest() self.pwd_hash = sha256(pwd).hexdigest()
u = User(pwd_hash=sha256(b"secret").hexdigest()) u: Any = User(pwd_hash=sha256(b"secret").hexdigest())
assert u.check_password(b"secret") assert u.check_password(b"secret")
assert not u.check_password(b"not-secret") assert not u.check_password(b"not-secret")
@@ -409,8 +418,8 @@ def test_docs_with_properties() -> None:
def test_nested_can_be_assigned_to() -> None: def test_nested_can_be_assigned_to() -> None:
d1 = DocWithNested(comments=[Comment(title="First!")]) d1: Any = DocWithNested(comments=[Comment(title="First!")])
d2 = DocWithNested() d2: Any = DocWithNested()
d2.comments = d1.comments d2.comments = d1.comments
assert isinstance(d1.comments[0], Comment) assert isinstance(d1.comments[0], Comment)
@@ -420,13 +429,13 @@ def test_nested_can_be_assigned_to() -> None:
def test_nested_can_be_none() -> None: def test_nested_can_be_none() -> None:
d = DocWithNested(comments=None, title="Hello World!") d: Any = DocWithNested(comments=None, title="Hello World!")
assert {"title": "Hello World!"} == d.to_dict() assert {"title": "Hello World!"} == d.to_dict()
def test_nested_defaults_to_list_and_can_be_updated() -> None: def test_nested_defaults_to_list_and_can_be_updated() -> None:
md = DocWithNested() md: Any = DocWithNested()
assert [] == md.comments assert [] == md.comments
@@ -434,8 +443,8 @@ def test_nested_defaults_to_list_and_can_be_updated() -> None:
assert {"comments": [{"title": "hello World!"}]} == md.to_dict() assert {"comments": [{"title": "hello World!"}]} == md.to_dict()
def test_to_dict_is_recursive_and_can_cope_with_multi_values(): def test_to_dict_is_recursive_and_can_cope_with_multi_values() -> None:
md = MyDoc(name=["a", "b", "c"]) md: Any = MyDoc(name=["a", "b", "c"])
md.inner = [MyInner(old_field="of1"), MyInner(old_field="of2")] md.inner = [MyInner(old_field="of1"), MyInner(old_field="of2")]
assert isinstance(md.inner[0], MyInner) assert isinstance(md.inner[0], MyInner)
@@ -447,12 +456,12 @@ def test_to_dict_is_recursive_and_can_cope_with_multi_values():
def test_to_dict_ignores_empty_collections() -> None: def test_to_dict_ignores_empty_collections() -> None:
md = MySubDoc(name="", address={}, count=0, valid=False, tags=[]) md: Any = MySubDoc(name="", address={}, count=0, valid=False, tags=[])
assert {"name": "", "count": 0, "valid": False} == md.to_dict() assert {"name": "", "count": 0, "valid": False} == md.to_dict()
def test_declarative_mapping_definition(): def test_declarative_mapping_definition() -> None:
assert issubclass(MyDoc, document.Document) assert issubclass(MyDoc, document.Document)
assert hasattr(MyDoc, "_doc_type") assert hasattr(MyDoc, "_doc_type")
assert { assert {
@@ -465,7 +474,7 @@ def test_declarative_mapping_definition():
} == MyDoc._doc_type.mapping.to_dict() } == MyDoc._doc_type.mapping.to_dict()
def test_you_can_supply_own_mapping_instance(): def test_you_can_supply_own_mapping_instance() -> None:
class MyD(document.Document): class MyD(document.Document):
title = field.Text() title = field.Text()
@@ -479,9 +488,9 @@ def test_you_can_supply_own_mapping_instance():
} == MyD._doc_type.mapping.to_dict() } == MyD._doc_type.mapping.to_dict()
def test_document_can_be_created_dynamically(): def test_document_can_be_created_dynamically() -> None:
n = datetime.now() n = datetime.now()
md = MyDoc(title="hello") md: Any = MyDoc(title="hello")
md.name = "My Fancy Document!" md.name = "My Fancy Document!"
md.created_at = n md.created_at = n
@@ -501,13 +510,13 @@ def test_document_can_be_created_dynamically():
def test_invalid_date_will_raise_exception() -> None: def test_invalid_date_will_raise_exception() -> None:
md = MyDoc() md: Any = MyDoc()
md.created_at = "not-a-date" md.created_at = "not-a-date"
with raises(ValidationException): with raises(ValidationException):
md.full_clean() md.full_clean()
def test_document_inheritance(): def test_document_inheritance() -> None:
assert issubclass(MySubDoc, MyDoc) assert issubclass(MySubDoc, MyDoc)
assert issubclass(MySubDoc, document.Document) assert issubclass(MySubDoc, document.Document)
assert hasattr(MySubDoc, "_doc_type") assert hasattr(MySubDoc, "_doc_type")
@@ -521,7 +530,7 @@ def test_document_inheritance():
} == MySubDoc._doc_type.mapping.to_dict() } == MySubDoc._doc_type.mapping.to_dict()
def test_child_class_can_override_parent(): def test_child_class_can_override_parent() -> None:
class A(document.Document): class A(document.Document):
o = field.Object(dynamic=False, properties={"a": field.Text()}) o = field.Object(dynamic=False, properties={"a": field.Text()})
@@ -540,7 +549,7 @@ def test_child_class_can_override_parent():
def test_meta_fields_are_stored_in_meta_and_ignored_by_to_dict() -> None: def test_meta_fields_are_stored_in_meta_and_ignored_by_to_dict() -> None:
md = MySubDoc(meta={"id": 42}, name="My First doc!") md: Any = MySubDoc(meta={"id": 42}, name="My First doc!")
md.meta.index = "my-index" md.meta.index = "my-index"
assert md.meta.index == "my-index" assert md.meta.index == "my-index"
@@ -549,7 +558,7 @@ def test_meta_fields_are_stored_in_meta_and_ignored_by_to_dict() -> None:
assert {"id": 42, "index": "my-index"} == md.meta.to_dict() assert {"id": 42, "index": "my-index"} == md.meta.to_dict()
def test_index_inheritance(): def test_index_inheritance() -> None:
assert issubclass(MyMultiSubDoc, MySubDoc) assert issubclass(MyMultiSubDoc, MySubDoc)
assert issubclass(MyMultiSubDoc, MyDoc2) assert issubclass(MyMultiSubDoc, MyDoc2)
assert issubclass(MyMultiSubDoc, document.Document) assert issubclass(MyMultiSubDoc, document.Document)
@@ -568,31 +577,31 @@ def test_index_inheritance():
def test_meta_fields_can_be_set_directly_in_init() -> None: def test_meta_fields_can_be_set_directly_in_init() -> None:
p = object() p = object()
md = MyDoc(_id=p, title="Hello World!") md: Any = MyDoc(_id=p, title="Hello World!")
assert md.meta.id is p assert md.meta.id is p
def test_save_no_index(mock_client) -> None: def test_save_no_index(mock_client: Any) -> None:
md = MyDoc() md: Any = MyDoc()
with raises(ValidationException): with raises(ValidationException):
md.save(using="mock") md.save(using="mock")
def test_delete_no_index(mock_client) -> None: def test_delete_no_index(mock_client: Any) -> None:
md = MyDoc() md: Any = MyDoc()
with raises(ValidationException): with raises(ValidationException):
md.delete(using="mock") md.delete(using="mock")
def test_update_no_fields() -> None: def test_update_no_fields() -> None:
md = MyDoc() md: Any = MyDoc()
with raises(IllegalOperation): with raises(IllegalOperation):
md.update() md.update()
def test_search_with_custom_alias_and_index(mock_client) -> None: def test_search_with_custom_alias_and_index(mock_client: Any) -> None:
search_object = MyDoc.search( search_object: Any = MyDoc.search(
using="staging", index=["custom_index1", "custom_index2"] using="staging", index=["custom_index1", "custom_index2"]
) )
@@ -600,7 +609,7 @@ def test_search_with_custom_alias_and_index(mock_client) -> None:
assert search_object._index == ["custom_index1", "custom_index2"] assert search_object._index == ["custom_index1", "custom_index2"]
def test_from_opensearch_respects_underscored_non_meta_fields(): def test_from_opensearch_respects_underscored_non_meta_fields() -> None:
doc = { doc = {
"_index": "test-index", "_index": "test-index",
"_id": "opensearch", "_id": "opensearch",
@@ -617,18 +626,18 @@ def test_from_opensearch_respects_underscored_non_meta_fields():
class Index: class Index:
name = "test-company" name = "test-company"
c = Company.from_opensearch(doc) c: Any = Company.from_opensearch(doc)
assert c.meta.fields._tags == ["search"] assert c.meta.fields._tags == ["search"]
assert c.meta.fields._routing == "opensearch" assert c.meta.fields._routing == "opensearch"
assert c._tagline == "You know, for search" assert c._tagline == "You know, for search"
def test_nested_and_object_inner_doc(): def test_nested_and_object_inner_doc() -> None:
class MySubDocWithNested(MyDoc): class MySubDocWithNested(MyDoc):
nested_inner = field.Nested(MyInner) nested_inner = field.Nested(MyInner)
props = MySubDocWithNested._doc_type.mapping.to_dict()["properties"] props: Any = MySubDocWithNested._doc_type.mapping.to_dict()["properties"]
assert props == { assert props == {
"created_at": {"type": "date"}, "created_at": {"type": "date"},
"inner": {"properties": {"old_field": {"type": "text"}}, "type": "object"}, "inner": {"properties": {"old_field": {"type": "text"}}, "type": "object"},
@@ -26,6 +26,7 @@
# under the License. # under the License.
from datetime import datetime from datetime import datetime
from typing import Any
import pytest import pytest
@@ -72,7 +73,7 @@ def test_query_is_created_properly() -> None:
} == s.to_dict() } == s.to_dict()
def test_query_is_created_properly_with_sort_tuple(): def test_query_is_created_properly_with_sort_tuple() -> None:
bs = BlogSearch("python search", sort=("category", "-title")) bs = BlogSearch("python search", sort=("category", "-title"))
s = bs.build_search() s = bs.build_search()
@@ -96,7 +97,7 @@ def test_query_is_created_properly_with_sort_tuple():
} == s.to_dict() } == s.to_dict()
def test_filter_is_applied_to_search_but_not_relevant_facet(): def test_filter_is_applied_to_search_but_not_relevant_facet() -> None:
bs = BlogSearch("python search", filters={"category": "opensearch"}) bs = BlogSearch("python search", filters={"category": "opensearch"})
s = bs.build_search() s = bs.build_search()
@@ -119,7 +120,7 @@ def test_filter_is_applied_to_search_but_not_relevant_facet():
} == s.to_dict() } == s.to_dict()
def test_filters_are_applied_to_search_ant_relevant_facets(): def test_filters_are_applied_to_search_ant_relevant_facets() -> None:
bs = BlogSearch( bs = BlogSearch(
"python search", "python search",
filters={"category": "opensearch", "tags": ["python", "django"]}, filters={"category": "opensearch", "tags": ["python", "django"]},
@@ -159,7 +160,7 @@ def test_date_histogram_facet_with_1970_01_01_date() -> None:
assert dhf.get_value({"key": 0}) == datetime(1970, 1, 1, 0, 0) assert dhf.get_value({"key": 0}) == datetime(1970, 1, 1, 0, 0)
@pytest.mark.parametrize( @pytest.mark.parametrize( # type: ignore
["interval_type", "interval"], ["interval_type", "interval"],
[ [
("interval", "year"), ("interval", "year"),
@@ -186,7 +187,7 @@ def test_date_histogram_facet_with_1970_01_01_date() -> None:
("fixed_interval", "1h"), ("fixed_interval", "1h"),
], ],
) )
def test_date_histogram_interval_types(interval_type, interval) -> None: def test_date_histogram_interval_types(interval_type: Any, interval: Any) -> None:
dhf = DateHistogramFacet(field="@timestamp", **{interval_type: interval}) dhf = DateHistogramFacet(field="@timestamp", **{interval_type: interval})
assert dhf.get_aggregation().to_dict() == { assert dhf.get_aggregation().to_dict() == {
"date_histogram": { "date_histogram": {
+8 -7
View File
@@ -28,6 +28,7 @@
import base64 import base64
from datetime import datetime from datetime import datetime
from ipaddress import ip_address from ipaddress import ip_address
from typing import Any
import pytest import pytest
from dateutil import tz from dateutil import tz
@@ -59,7 +60,7 @@ def test_boolean_deserialization() -> None:
def test_date_field_can_have_default_tz() -> None: def test_date_field_can_have_default_tz() -> None:
f = field.Date(default_timezone="UTC") f: Any = field.Date(default_timezone="UTC")
now = datetime.now() now = datetime.now()
now_with_tz = f._deserialize(now) now_with_tz = f._deserialize(now)
@@ -76,7 +77,7 @@ def test_date_field_can_have_default_tz() -> None:
def test_custom_field_car_wrap_other_field() -> None: def test_custom_field_car_wrap_other_field() -> None:
class MyField(field.CustomField): class MyField(field.CustomField):
@property @property
def builtin_type(self): def builtin_type(self) -> Any:
return field.Text(**self._params) return field.Text(**self._params)
assert {"type": "text", "index": "not_analyzed"} == MyField( assert {"type": "text", "index": "not_analyzed"} == MyField(
@@ -91,7 +92,7 @@ def test_field_from_dict() -> None:
assert {"type": "text", "index": "not_analyzed"} == f.to_dict() assert {"type": "text", "index": "not_analyzed"} == f.to_dict()
def test_multi_fields_are_accepted_and_parsed(): def test_multi_fields_are_accepted_and_parsed() -> None:
f = field.construct_field( f = field.construct_field(
"text", "text",
fields={"raw": {"type": "keyword"}, "eng": field.Text(analyzer="english")}, fields={"raw": {"type": "keyword"}, "eng": field.Text(analyzer="english")},
@@ -123,7 +124,7 @@ def test_field_supports_multiple_analyzers() -> None:
} == f.to_dict() } == f.to_dict()
def test_multifield_supports_multiple_analyzers(): def test_multifield_supports_multiple_analyzers() -> None:
f = field.Text( f = field.Text(
fields={ fields={
"f1": field.Text(search_analyzer="keyword", analyzer="snowball"), "f1": field.Text(search_analyzer="keyword", analyzer="snowball"),
@@ -145,8 +146,8 @@ def test_multifield_supports_multiple_analyzers():
def test_scaled_float() -> None: def test_scaled_float() -> None:
with pytest.raises(TypeError): with pytest.raises(TypeError):
field.ScaledFloat() field.ScaledFloat() # type: ignore
f = field.ScaledFloat(123) f: Any = field.ScaledFloat(scaling_factor=123)
assert f.to_dict() == {"scaling_factor": 123, "type": "scaled_float"} assert f.to_dict() == {"scaling_factor": 123, "type": "scaled_float"}
@@ -204,7 +205,7 @@ def test_object_disabled() -> None:
assert f.to_dict() == {"type": "object", "enabled": False} assert f.to_dict() == {"type": "object", "enabled": False}
def test_object_constructor(): def test_object_constructor() -> None:
expected = {"type": "object", "properties": {"inner_int": {"type": "integer"}}} expected = {"type": "object", "properties": {"inner_int": {"type": "integer"}}}
class Inner(InnerDoc): class Inner(InnerDoc):
+19 -18
View File
@@ -27,6 +27,7 @@
import string import string
from random import choice from random import choice
from typing import Any
from pytest import raises from pytest import raises
@@ -65,7 +66,7 @@ def test_search_is_limited_to_index_name() -> None:
def test_cloned_index_has_copied_settings_and_using() -> None: def test_cloned_index_has_copied_settings_and_using() -> None:
client = object() client = object()
i = Index("my-index", using=client) i: Any = Index("my-index", using=client)
i.settings(number_of_shards=1) i.settings(number_of_shards=1)
i2 = i.clone("my-other-index") i2 = i.clone("my-other-index")
@@ -82,7 +83,7 @@ def test_cloned_index_has_analysis_attribute() -> None:
over the `_analysis` attribute. over the `_analysis` attribute.
""" """
client = object() client = object()
i = Index("my-index", using=client) i: Any = Index("my-index", using=client)
random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100))) random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100)))
random_analyzer = analyzer( random_analyzer = analyzer(
@@ -97,7 +98,7 @@ def test_cloned_index_has_analysis_attribute() -> None:
def test_settings_are_saved() -> None: def test_settings_are_saved() -> None:
i = Index("i") i: Any = Index("i")
i.settings(number_of_replicas=0) i.settings(number_of_replicas=0)
i.settings(number_of_shards=1) i.settings(number_of_shards=1)
@@ -105,7 +106,7 @@ def test_settings_are_saved() -> None:
def test_registered_doc_type_included_in_to_dict() -> None: def test_registered_doc_type_included_in_to_dict() -> None:
i = Index("i", using="alias") i: Any = Index("i", using="alias")
i.document(Post) i.document(Post)
assert { assert {
@@ -119,7 +120,7 @@ def test_registered_doc_type_included_in_to_dict() -> None:
def test_registered_doc_type_included_in_search() -> None: def test_registered_doc_type_included_in_search() -> None:
i = Index("i", using="alias") i: Any = Index("i", using="alias")
i.document(Post) i.document(Post)
s = i.search() s = i.search()
@@ -129,9 +130,9 @@ def test_registered_doc_type_included_in_search() -> None:
def test_aliases_add_to_object() -> None: def test_aliases_add_to_object() -> None:
random_alias = "".join((choice(string.ascii_letters) for _ in range(100))) random_alias = "".join((choice(string.ascii_letters) for _ in range(100)))
alias_dict = {random_alias: {}} alias_dict: Any = {random_alias: {}}
index = Index("i", using="alias") index: Any = Index("i", using="alias")
index.aliases(**alias_dict) index.aliases(**alias_dict)
assert index._aliases == alias_dict assert index._aliases == alias_dict
@@ -139,21 +140,21 @@ def test_aliases_add_to_object() -> None:
def test_aliases_returned_from_to_dict() -> None: def test_aliases_returned_from_to_dict() -> None:
random_alias = "".join((choice(string.ascii_letters) for _ in range(100))) random_alias = "".join((choice(string.ascii_letters) for _ in range(100)))
alias_dict = {random_alias: {}} alias_dict: Any = {random_alias: {}}
index = Index("i", using="alias") index: Any = Index("i", using="alias")
index.aliases(**alias_dict) index.aliases(**alias_dict)
assert index._aliases == index.to_dict()["aliases"] == alias_dict assert index._aliases == index.to_dict()["aliases"] == alias_dict
def test_analyzers_added_to_object(): def test_analyzers_added_to_object() -> None:
random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100))) random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100)))
random_analyzer = analyzer( random_analyzer = analyzer(
random_analyzer_name, tokenizer="standard", filter="standard" random_analyzer_name, tokenizer="standard", filter="standard"
) )
index = Index("i", using="alias") index: Any = Index("i", using="alias")
index.analyzer(random_analyzer) index.analyzer(random_analyzer)
assert index._analysis["analyzer"][random_analyzer_name] == { assert index._analysis["analyzer"][random_analyzer_name] == {
@@ -163,12 +164,12 @@ def test_analyzers_added_to_object():
} }
def test_analyzers_returned_from_to_dict(): def test_analyzers_returned_from_to_dict() -> None:
random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100))) random_analyzer_name = "".join((choice(string.ascii_letters) for _ in range(100)))
random_analyzer = analyzer( random_analyzer = analyzer(
random_analyzer_name, tokenizer="standard", filter="standard" random_analyzer_name, tokenizer="standard", filter="standard"
) )
index = Index("i", using="alias") index: Any = Index("i", using="alias")
index.analyzer(random_analyzer) index.analyzer(random_analyzer)
assert index.to_dict()["settings"]["analysis"]["analyzer"][ assert index.to_dict()["settings"]["analysis"]["analyzer"][
@@ -177,21 +178,21 @@ def test_analyzers_returned_from_to_dict():
def test_conflicting_analyzer_raises_error() -> None: def test_conflicting_analyzer_raises_error() -> None:
i = Index("i") i: Any = Index("i")
i.analyzer("my_analyzer", tokenizer="whitespace", filter=["lowercase", "stop"]) i.analyzer("my_analyzer", tokenizer="whitespace", filter=["lowercase", "stop"])
with raises(ValueError): with raises(ValueError):
i.analyzer("my_analyzer", tokenizer="keyword", filter=["lowercase", "stop"]) i.analyzer("my_analyzer", tokenizer="keyword", filter=["lowercase", "stop"])
def test_index_template_can_have_order(): def test_index_template_can_have_order() -> None:
i = Index("i-*") i: Any = Index("i-*")
it = i.as_template("i", order=2) it = i.as_template("i", order=2)
assert {"index_patterns": ["i-*"], "order": 2} == it.to_dict() assert {"index_patterns": ["i-*"], "order": 2} == it.to_dict()
def test_index_template_save_result(mock_client) -> None: def test_index_template_save_result(mock_client: Any) -> None:
it = IndexTemplate("test-template", "test-*") it: Any = IndexTemplate("test-template", "test-*")
assert it.save(using="mock") == mock_client.indices.put_template() assert it.save(using="mock") == mock_client.indices.put_template()
@@ -40,7 +40,7 @@ def test_mapping_can_has_fields() -> None:
} == m.to_dict() } == m.to_dict()
def test_mapping_update_is_recursive(): def test_mapping_update_is_recursive() -> None:
m1 = mapping.Mapping() m1 = mapping.Mapping()
m1.field("title", "text") m1.field("title", "text")
m1.field("author", "object") m1.field("author", "object")
@@ -83,7 +83,7 @@ def test_properties_can_iterate_over_all_the_fields() -> None:
} }
def test_mapping_can_collect_all_analyzers_and_normalizers(): def test_mapping_can_collect_all_analyzers_and_normalizers() -> None:
a1 = analysis.analyzer( a1 = analysis.analyzer(
"my_analyzer1", "my_analyzer1",
tokenizer="keyword", tokenizer="keyword",
@@ -156,7 +156,7 @@ def test_mapping_can_collect_all_analyzers_and_normalizers():
assert json.loads(json.dumps(m.to_dict())) == m.to_dict() assert json.loads(json.dumps(m.to_dict())) == m.to_dict()
def test_mapping_can_collect_multiple_analyzers(): def test_mapping_can_collect_multiple_analyzers() -> None:
a1 = analysis.analyzer( a1 = analysis.analyzer(
"my_analyzer1", "my_analyzer1",
tokenizer="keyword", tokenizer="keyword",
+8 -6
View File
@@ -25,6 +25,8 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
from typing import Any
from pytest import raises from pytest import raises
from opensearchpy.helpers import function, query from opensearchpy.helpers import function, query
@@ -122,8 +124,8 @@ def test_other_and_bool_appends_other_to_must() -> None:
def test_bool_and_other_appends_other_to_must() -> None: def test_bool_and_other_appends_other_to_must() -> None:
q1 = query.Match(f="value1") q1: Any = query.Match(f="value1")
qb = query.Bool() qb: Any = query.Bool()
q = qb & q1 q = qb & q1
assert q is not qb assert q is not qb
@@ -463,7 +465,7 @@ def test_function_score_with_functions() -> None:
} == q.to_dict() } == q.to_dict()
def test_function_score_with_no_function_is_boost_factor(): def test_function_score_with_no_function_is_boost_factor() -> None:
q = query.Q( q = query.Q(
"function_score", "function_score",
functions=[query.SF({"weight": 20, "filter": query.Q("term", f=42)})], functions=[query.SF({"weight": 20, "filter": query.Q("term", f=42)})],
@@ -474,7 +476,7 @@ def test_function_score_with_no_function_is_boost_factor():
} == q.to_dict() } == q.to_dict()
def test_function_score_to_dict(): def test_function_score_to_dict() -> None:
q = query.Q( q = query.Q(
"function_score", "function_score",
query=query.Q("match", title="python"), query=query.Q("match", title="python"),
@@ -503,7 +505,7 @@ def test_function_score_to_dict():
assert d == q.to_dict() assert d == q.to_dict()
def test_function_score_with_single_function(): def test_function_score_with_single_function() -> None:
d = { d = {
"function_score": { "function_score": {
"filter": {"term": {"tags": "python"}}, "filter": {"term": {"tags": "python"}},
@@ -521,7 +523,7 @@ def test_function_score_with_single_function():
assert "doc['comment_count'] * _score" == sf.script assert "doc['comment_count'] * _score" == sf.script
def test_function_score_from_dict(): def test_function_score_from_dict() -> None:
d = { d = {
"function_score": { "function_score": {
"filter": {"term": {"tags": "python"}}, "filter": {"term": {"tags": "python"}},
+22 -19
View File
@@ -27,6 +27,7 @@
import pickle import pickle
from datetime import date from datetime import date
from typing import Any
from pytest import fixture, raises from pytest import fixture, raises
@@ -36,12 +37,12 @@ from opensearchpy.helpers.aggs import Terms
from opensearchpy.helpers.response.aggs import AggResponse, Bucket, BucketData from opensearchpy.helpers.response.aggs import AggResponse, Bucket, BucketData
@fixture @fixture # type: ignore
def agg_response(aggs_search, aggs_data): def agg_response(aggs_search: Any, aggs_data: Any) -> Any:
return response.Response(aggs_search, aggs_data) return response.Response(aggs_search, aggs_data)
def test_agg_response_is_pickleable(agg_response) -> None: def test_agg_response_is_pickleable(agg_response: Any) -> None:
agg_response.hits agg_response.hits
r = pickle.loads(pickle.dumps(agg_response)) r = pickle.loads(pickle.dumps(agg_response))
@@ -50,7 +51,7 @@ def test_agg_response_is_pickleable(agg_response) -> None:
assert r.hits == agg_response.hits assert r.hits == agg_response.hits
def test_response_is_pickleable(dummy_response) -> None: def test_response_is_pickleable(dummy_response: Any) -> None:
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
res.hits res.hits
r = pickle.loads(pickle.dumps(res)) r = pickle.loads(pickle.dumps(res))
@@ -60,7 +61,7 @@ def test_response_is_pickleable(dummy_response) -> None:
assert r.hits == res.hits assert r.hits == res.hits
def test_hit_is_pickleable(dummy_response) -> None: def test_hit_is_pickleable(dummy_response: Any) -> None:
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
hits = pickle.loads(pickle.dumps(res.hits)) hits = pickle.loads(pickle.dumps(res.hits))
@@ -68,14 +69,14 @@ def test_hit_is_pickleable(dummy_response) -> None:
assert hits[0].meta == res.hits[0].meta assert hits[0].meta == res.hits[0].meta
def test_response_stores_search(dummy_response) -> None: def test_response_stores_search(dummy_response: Any) -> None:
s = Search() s = Search()
r = response.Response(s, dummy_response) r = response.Response(s, dummy_response)
assert r._search is s assert r._search is s
def test_interactive_helpers(dummy_response) -> None: def test_interactive_helpers(dummy_response: Any) -> None:
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
hits = res.hits hits = res.hits
h = hits[0] h = hits[0]
@@ -98,19 +99,19 @@ def test_interactive_helpers(dummy_response) -> None:
] == repr(h) ] == repr(h)
def test_empty_response_is_false(dummy_response) -> None: def test_empty_response_is_false(dummy_response: Any) -> None:
dummy_response["hits"]["hits"] = [] dummy_response["hits"]["hits"] = []
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
assert not res assert not res
def test_len_response(dummy_response) -> None: def test_len_response(dummy_response: Any) -> None:
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
assert len(res) == 4 assert len(res) == 4
def test_iterating_over_response_gives_you_hits(dummy_response) -> None: def test_iterating_over_response_gives_you_hits(dummy_response: Any) -> None:
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
hits = list(h for h in res) hits = list(h for h in res)
@@ -127,7 +128,7 @@ def test_iterating_over_response_gives_you_hits(dummy_response) -> None:
assert hits[1].meta.routing == "opensearch" assert hits[1].meta.routing == "opensearch"
def test_hits_get_wrapped_to_contain_additional_attrs(dummy_response) -> None: def test_hits_get_wrapped_to_contain_additional_attrs(dummy_response: Any) -> None:
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
hits = res.hits hits = res.hits
@@ -135,7 +136,7 @@ def test_hits_get_wrapped_to_contain_additional_attrs(dummy_response) -> None:
assert 12.0 == hits.max_score assert 12.0 == hits.max_score
def test_hits_provide_dot_and_bracket_access_to_attrs(dummy_response) -> None: def test_hits_provide_dot_and_bracket_access_to_attrs(dummy_response: Any) -> None:
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
h = res.hits[0] h = res.hits[0]
@@ -151,30 +152,32 @@ def test_hits_provide_dot_and_bracket_access_to_attrs(dummy_response) -> None:
h.not_there h.not_there
def test_slicing_on_response_slices_on_hits(dummy_response) -> None: def test_slicing_on_response_slices_on_hits(dummy_response: Any) -> None:
res = response.Response(Search(), dummy_response) res = response.Response(Search(), dummy_response)
assert res[0] is res.hits[0] assert res[0] is res.hits[0]
assert res[::-1] == res.hits[::-1] assert res[::-1] == res.hits[::-1]
def test_aggregation_base(agg_response) -> None: def test_aggregation_base(agg_response: Any) -> None:
assert agg_response.aggs is agg_response.aggregations assert agg_response.aggs is agg_response.aggregations
assert isinstance(agg_response.aggs, response.AggResponse) assert isinstance(agg_response.aggs, response.AggResponse)
def test_metric_agg_works(agg_response) -> None: def test_metric_agg_works(agg_response: Any) -> None:
assert 25052.0 == agg_response.aggs.sum_lines.value assert 25052.0 == agg_response.aggs.sum_lines.value
def test_aggregations_can_be_iterated_over(agg_response) -> None: def test_aggregations_can_be_iterated_over(agg_response: Any) -> None:
aggs = [a for a in agg_response.aggs] aggs = [a for a in agg_response.aggs]
assert len(aggs) == 3 assert len(aggs) == 3
assert all(map(lambda a: isinstance(a, AggResponse), aggs)) assert all(map(lambda a: isinstance(a, AggResponse), aggs))
def test_aggregations_can_be_retrieved_by_name(agg_response, aggs_search) -> None: def test_aggregations_can_be_retrieved_by_name(
agg_response: Any, aggs_search: Any
) -> None:
a = agg_response.aggs["popular_files"] a = agg_response.aggs["popular_files"]
assert isinstance(a, BucketData) assert isinstance(a, BucketData)
@@ -182,7 +185,7 @@ def test_aggregations_can_be_retrieved_by_name(agg_response, aggs_search) -> Non
assert a._meta["aggs"] is aggs_search.aggs.aggs["popular_files"] assert a._meta["aggs"] is aggs_search.aggs.aggs["popular_files"]
def test_bucket_response_can_be_iterated_over(agg_response) -> None: def test_bucket_response_can_be_iterated_over(agg_response: Any) -> None:
popular_files = agg_response.aggregations.popular_files popular_files = agg_response.aggregations.popular_files
buckets = [b for b in popular_files] buckets = [b for b in popular_files]
@@ -190,7 +193,7 @@ def test_bucket_response_can_be_iterated_over(agg_response) -> None:
assert buckets == popular_files.buckets assert buckets == popular_files.buckets
def test_bucket_keys_get_deserialized(aggs_data, aggs_search) -> None: def test_bucket_keys_get_deserialized(aggs_data: Any, aggs_search: Any) -> None:
class Commit(Document): class Commit(Document):
info = Object(properties={"committed_date": Date()}) info = Object(properties={"committed_date": Date()})
+39 -38
View File
@@ -26,6 +26,7 @@
# under the License. # under the License.
from copy import deepcopy from copy import deepcopy
from typing import Any
from pytest import raises from pytest import raises
@@ -41,16 +42,16 @@ def test_expand__to_dot_is_respected() -> None:
def test_execute_uses_cache() -> None: def test_execute_uses_cache() -> None:
s = search.Search() s: Any = search.Search()
r = object() r: Any = object()
s._response = r s._response = r
assert r is s.execute() assert r is s.execute()
def test_cache_can_be_ignored(mock_client) -> None: def test_cache_can_be_ignored(mock_client: Any) -> None:
s = search.Search(using="mock") s: Any = search.Search(using="mock")
r = object() r: Any = object()
s._response = r s._response = r
s.execute(ignore_cache=True) s.execute(ignore_cache=True)
@@ -58,27 +59,27 @@ def test_cache_can_be_ignored(mock_client) -> None:
def test_iter_iterates_over_hits() -> None: def test_iter_iterates_over_hits() -> None:
s = search.Search() s: Any = search.Search()
s._response = [1, 2, 3] s._response = [1, 2, 3]
assert [1, 2, 3] == list(s) assert [1, 2, 3] == list(s)
def test_cache_isnt_cloned() -> None: def test_cache_isnt_cloned() -> None:
s = search.Search() s: Any = search.Search()
s._response = object() s._response = object()
assert not hasattr(s._clone(), "_response") assert not hasattr(s._clone(), "_response")
def test_search_starts_with_no_query() -> None: def test_search_starts_with_no_query() -> None:
s = search.Search() s: Any = search.Search()
assert s.query._proxied is None assert s.query._proxied is None
def test_search_query_combines_query() -> None: def test_search_query_combines_query() -> None:
s = search.Search() s: Any = search.Search()
s2 = s.query("match", f=42) s2 = s.query("match", f=42)
assert s2.query._proxied == query.Match(f=42) assert s2.query._proxied == query.Match(f=42)
@@ -90,7 +91,7 @@ def test_search_query_combines_query() -> None:
def test_query_can_be_assigned_to() -> None: def test_query_can_be_assigned_to() -> None:
s = search.Search() s: Any = search.Search()
q = Q("match", title="python") q = Q("match", title="python")
s.query = q s.query = q
@@ -98,8 +99,8 @@ def test_query_can_be_assigned_to() -> None:
assert s.query._proxied is q assert s.query._proxied is q
def test_query_can_be_wrapped(): def test_query_can_be_wrapped() -> None:
s = search.Search().query("match", title="python") s: Any = search.Search().query("match", title="python")
s.query = Q("function_score", query=s.query, field_value_factor={"field": "rating"}) s.query = Q("function_score", query=s.query, field_value_factor={"field": "rating"})
@@ -114,9 +115,9 @@ def test_query_can_be_wrapped():
def test_using() -> None: def test_using() -> None:
o = object() o: Any = object()
o2 = object() o2: Any = object()
s = search.Search(using=o) s: Any = search.Search(using=o)
assert s._using is o assert s._using is o
s2 = s.using(o2) s2 = s.using(o2)
assert s._using is o assert s._using is o
@@ -124,27 +125,27 @@ def test_using() -> None:
def test_methods_are_proxied_to_the_query() -> None: def test_methods_are_proxied_to_the_query() -> None:
s = search.Search().query("match_all") s: Any = search.Search().query("match_all")
assert s.query.to_dict() == {"match_all": {}} assert s.query.to_dict() == {"match_all": {}}
def test_query_always_returns_search() -> None: def test_query_always_returns_search() -> None:
s = search.Search() s: Any = search.Search()
assert isinstance(s.query("match", f=42), search.Search) assert isinstance(s.query("match", f=42), search.Search)
def test_source_copied_on_clone() -> None: def test_source_copied_on_clone() -> None:
s = search.Search().source(False) s: Any = search.Search().source(False)
assert s._clone()._source == s._source assert s._clone()._source == s._source
assert s._clone()._source is False assert s._clone()._source is False
s2 = search.Search().source([]) s2: Any = search.Search().source([])
assert s2._clone()._source == s2._source assert s2._clone()._source == s2._source
assert s2._source == [] assert s2._source == []
s3 = search.Search().source(["some", "fields"]) s3: Any = search.Search().source(["some", "fields"])
assert s3._clone()._source == s3._source assert s3._clone()._source == s3._source
assert s3._clone()._source == ["some", "fields"] assert s3._clone()._source == ["some", "fields"]
@@ -152,15 +153,15 @@ def test_source_copied_on_clone() -> None:
def test_copy_clones() -> None: def test_copy_clones() -> None:
from copy import copy from copy import copy
s1 = search.Search().source(["some", "fields"]) s1: Any = search.Search().source(["some", "fields"])
s2 = copy(s1) s2: Any = copy(s1)
assert s1 == s2 assert s1 == s2
assert s1 is not s2 assert s1 is not s2
def test_aggs_allow_two_metric() -> None: def test_aggs_allow_two_metric() -> None:
s = search.Search() s: Any = search.Search()
s.aggs.metric("a", "max", field="a").metric("b", "max", field="b") s.aggs.metric("a", "max", field="a").metric("b", "max", field="b")
@@ -169,8 +170,8 @@ def test_aggs_allow_two_metric() -> None:
} }
def test_aggs_get_copied_on_change(): def test_aggs_get_copied_on_change() -> None:
s = search.Search().query("match_all") s: Any = search.Search().query("match_all")
s.aggs.bucket("per_tag", "terms", field="f").metric( s.aggs.bucket("per_tag", "terms", field="f").metric(
"max_score", "max", field="score" "max_score", "max", field="score"
) )
@@ -182,7 +183,7 @@ def test_aggs_get_copied_on_change():
s4 = s3._clone() s4 = s3._clone()
s4.aggs.metric("max_score", "max", field="score") s4.aggs.metric("max_score", "max", field="score")
d = { d: Any = {
"query": {"match_all": {}}, "query": {"match_all": {}},
"aggs": { "aggs": {
"per_tag": { "per_tag": {
@@ -245,7 +246,7 @@ def test_doc_type_document_class() -> None:
assert s._doc_type_map == {} assert s._doc_type_map == {}
def test_sort(): def test_sort() -> None:
s = search.Search() s = search.Search()
s = s.sort("fielda", "-fieldb") s = s.sort("fielda", "-fieldb")
@@ -267,7 +268,7 @@ def test_sort_by_score() -> None:
s.sort("-_score") s.sort("-_score")
def test_collapse(): def test_collapse() -> None:
s = search.Search() s = search.Search()
inner_hits = {"name": "most_recent", "size": 5, "sort": [{"@timestamp": "desc"}]} inner_hits = {"name": "most_recent", "size": 5, "sort": [{"@timestamp": "desc"}]}
@@ -315,7 +316,7 @@ def test_index() -> None:
assert {"from": 3, "size": 1} == s[3].to_dict() assert {"from": 3, "size": 1} == s[3].to_dict()
def test_search_to_dict(): def test_search_to_dict() -> None:
s = search.Search() s = search.Search()
assert {} == s.to_dict() assert {} == s.to_dict()
@@ -344,7 +345,7 @@ def test_search_to_dict():
assert {"size": 5, "from": 42} == s.to_dict() assert {"size": 5, "from": 42} == s.to_dict()
def test_complex_example(): def test_complex_example() -> None:
s = search.Search() s = search.Search()
s = ( s = (
s.query("match", title="python") s.query("match", title="python")
@@ -395,7 +396,7 @@ def test_complex_example():
} == s.to_dict() } == s.to_dict()
def test_reverse(): def test_reverse() -> None:
d = { d = {
"query": { "query": {
"filtered": { "filtered": {
@@ -451,7 +452,7 @@ def test_from_dict_doesnt_need_query() -> None:
assert {"size": 5} == s.to_dict() assert {"size": 5} == s.to_dict()
def test_params_being_passed_to_search(mock_client) -> None: def test_params_being_passed_to_search(mock_client: Any) -> None:
s = search.Search(using="mock") s = search.Search(using="mock")
s = s.params(routing="42") s = s.params(routing="42")
s.execute() s.execute()
@@ -473,7 +474,7 @@ def test_source() -> None:
).source(["f1", "f2"]).to_dict() ).source(["f1", "f2"]).to_dict()
def test_source_on_clone(): def test_source_on_clone() -> None:
assert { assert {
"_source": {"includes": ["foo.bar.*"], "excludes": ["foo.one"]}, "_source": {"includes": ["foo.bar.*"], "excludes": ["foo.one"]},
"query": {"bool": {"filter": [{"term": {"title": "python"}}]}}, "query": {"bool": {"filter": [{"term": {"title": "python"}}]}},
@@ -498,7 +499,7 @@ def test_source_on_clear() -> None:
) )
def test_suggest_accepts_global_text(): def test_suggest_accepts_global_text() -> None:
s = search.Search.from_dict( s = search.Search.from_dict(
{ {
"suggest": { "suggest": {
@@ -520,7 +521,7 @@ def test_suggest_accepts_global_text():
} == s.to_dict() } == s.to_dict()
def test_suggest(): def test_suggest() -> None:
s = search.Search() s = search.Search()
s = s.suggest("my_suggestion", "pyhton", term={"field": "title"}) s = s.suggest("my_suggestion", "pyhton", term={"field": "title"})
@@ -542,7 +543,7 @@ def test_exclude() -> None:
} == s.to_dict() } == s.to_dict()
def test_delete_by_query(mock_client) -> None: def test_delete_by_query(mock_client: Any) -> None:
s = search.Search(using="mock").query("match", lang="java") s = search.Search(using="mock").query("match", lang="java")
s.delete() s.delete()
@@ -551,7 +552,7 @@ def test_delete_by_query(mock_client) -> None:
) )
def test_update_from_dict(): def test_update_from_dict() -> None:
s = search.Search() s = search.Search()
s.update_from_dict({"indices_boost": [{"important-documents": 2}]}) s.update_from_dict({"indices_boost": [{"important-documents": 2}]})
s.update_from_dict({"_source": ["id", "name"]}) s.update_from_dict({"_source": ["id", "name"]})
@@ -562,7 +563,7 @@ def test_update_from_dict():
} == s.to_dict() } == s.to_dict()
def test_rescore_query_to_dict(): def test_rescore_query_to_dict() -> None:
s = search.Search(index="index-name") s = search.Search(index="index-name")
positive_query = Q( positive_query = Q(
@@ -26,6 +26,7 @@
# under the License. # under the License.
from copy import deepcopy from copy import deepcopy
from typing import Any
from opensearchpy import Q, UpdateByQuery from opensearchpy import Q, UpdateByQuery
from opensearchpy.helpers.response import UpdateByQueryResponse from opensearchpy.helpers.response import UpdateByQueryResponse
@@ -37,7 +38,7 @@ def test_ubq_starts_with_no_query() -> None:
assert ubq.query._proxied is None assert ubq.query._proxied is None
def test_ubq_to_dict(): def test_ubq_to_dict() -> None:
ubq = UpdateByQuery() ubq = UpdateByQuery()
assert {} == ubq.to_dict() assert {} == ubq.to_dict()
@@ -53,7 +54,7 @@ def test_ubq_to_dict():
assert {"extra_q": {"term": {"category": "conference"}}} == ubq.to_dict() assert {"extra_q": {"term": {"category": "conference"}}} == ubq.to_dict()
def test_complex_example(): def test_complex_example() -> None:
ubq = UpdateByQuery() ubq = UpdateByQuery()
ubq = ( ubq = (
ubq.query("match", title="python") ubq.query("match", title="python")
@@ -104,7 +105,7 @@ def test_exclude() -> None:
} == ubq.to_dict() } == ubq.to_dict()
def test_reverse(): def test_reverse() -> None:
d = { d = {
"query": { "query": {
"filtered": { "filtered": {
@@ -146,7 +147,7 @@ def test_from_dict_doesnt_need_query() -> None:
assert {"script": {"source": "test"}} == ubq.to_dict() assert {"script": {"source": "test"}} == ubq.to_dict()
def test_params_being_passed_to_search(mock_client) -> None: def test_params_being_passed_to_search(mock_client: Any) -> None:
ubq = UpdateByQuery(using="mock") ubq = UpdateByQuery(using="mock")
ubq = ubq.params(routing="42") ubq = ubq.params(routing="42")
ubq.execute() ubq.execute()
@@ -156,7 +157,7 @@ def test_params_being_passed_to_search(mock_client) -> None:
) )
def test_overwrite_script(): def test_overwrite_script() -> None:
ubq = UpdateByQuery() ubq = UpdateByQuery()
ubq = ubq.script( ubq = ubq.script(
source="ctx._source.likes += params.f", lang="painless", params={"f": 3} source="ctx._source.likes += params.f", lang="painless", params={"f": 3}
+2 -2
View File
@@ -55,7 +55,7 @@ def test_attrlist_slice() -> None:
assert isinstance(ls[:][0], MyAttrDict) assert isinstance(ls[:][0], MyAttrDict)
def test_merge(): def test_merge() -> None:
a = utils.AttrDict({"a": {"b": 42, "c": 47}}) a = utils.AttrDict({"a": {"b": 42, "c": 47}})
b = {"a": {"b": 123, "d": -12}, "e": [1, 2, 3]} b = {"a": {"b": 123, "d": -12}, "e": [1, 2, 3]}
@@ -101,7 +101,7 @@ def test_serializer_deals_with_Attr_versions() -> None:
def test_serializer_deals_with_objects_with_to_dict() -> None: def test_serializer_deals_with_objects_with_to_dict() -> None:
class MyClass(object): class MyClass(object):
def to_dict(self): def to_dict(self) -> int:
return 42 return 42
assert serializer.serializer.dumps(MyClass()) == "42" assert serializer.serializer.dumps(MyClass()) == "42"
@@ -26,6 +26,7 @@
# under the License. # under the License.
from datetime import datetime from datetime import datetime
from typing import Any
from pytest import raises from pytest import raises
@@ -43,8 +44,8 @@ from opensearchpy.exceptions import ValidationException
class Author(InnerDoc): class Author(InnerDoc):
name = Text(required=True) name: Any = Text(required=True)
email = Text(required=True) email: Any = Text(required=True)
def clean(self) -> None: def clean(self) -> None:
print(self, type(self), self.name) print(self, type(self), self.name)
@@ -63,7 +64,7 @@ class BlogPostWithStatus(Document):
class AutoNowDate(Date): class AutoNowDate(Date):
def clean(self, data): def clean(self, data: Any) -> Any:
if data is None: if data is None:
data = datetime.now() data = datetime.now()
return super(AutoNowDate, self).clean(data) return super(AutoNowDate, self).clean(data)
@@ -78,7 +79,7 @@ def test_required_int_can_be_0() -> None:
class DT(Document): class DT(Document):
i = Integer(required=True) i = Integer(required=True)
dt = DT(i=0) dt: Any = DT(i=0)
assert dt.full_clean() is None assert dt.full_clean() is None
@@ -95,12 +96,12 @@ def test_validation_works_for_lists_of_values() -> None:
class DT(Document): class DT(Document):
i = Date(required=True) i = Date(required=True)
dt = DT(i=[datetime.now(), "not date"]) dt1: Any = DT(i=[datetime.now(), "not date"])
with raises(ValidationException): with raises(ValidationException):
dt.full_clean() dt1.full_clean()
dt = DT(i=[datetime.now(), datetime.now()]) dt2: Any = DT(i=[datetime.now(), datetime.now()])
assert None is dt.full_clean() assert None is dt2.full_clean()
def test_field_with_custom_clean() -> None: def test_field_with_custom_clean() -> None:
@@ -111,29 +112,29 @@ def test_field_with_custom_clean() -> None:
def test_empty_object() -> None: def test_empty_object() -> None:
d = BlogPost(authors=[{"name": "Guian", "email": "[email protected]"}]) d: Any = BlogPost(authors=[{"name": "Guian", "email": "[email protected]"}])
d.inner = {} d.inner = {}
d.full_clean() d.full_clean()
def test_missing_required_field_raises_validation_exception() -> None: def test_missing_required_field_raises_validation_exception() -> None:
d = BlogPost() d1: Any = BlogPost()
with raises(ValidationException): with raises(ValidationException):
d.full_clean() d1.full_clean()
d = BlogPost() d2: Any = BlogPost()
d.authors.append({"name": "Guian"}) d2.authors.append({"name": "Guian"})
with raises(ValidationException): with raises(ValidationException):
d.full_clean() d2.full_clean()
d = BlogPost() d3: Any = BlogPost()
d.authors.append({"name": "Guian", "email": "[email protected]"}) d3.authors.append({"name": "Guian", "email": "[email protected]"})
d.full_clean() d3.full_clean()
def test_boolean_doesnt_treat_false_as_empty() -> None: def test_boolean_doesnt_treat_false_as_empty() -> None:
d = BlogPostWithStatus() d: Any = BlogPostWithStatus()
with raises(ValidationException): with raises(ValidationException):
d.full_clean() d.full_clean()
d.published = False d.published = False
@@ -143,7 +144,9 @@ def test_boolean_doesnt_treat_false_as_empty() -> None:
def test_custom_validation_on_nested_gets_run() -> None: def test_custom_validation_on_nested_gets_run() -> None:
d = BlogPost(authors=[Author(name="Guian", email="[email protected]")], created=None) d: Any = BlogPost(
authors=[Author(name="Guian", email="[email protected]")], created=None
)
assert isinstance(d.authors[0], Author) assert isinstance(d.authors[0], Author)
@@ -152,7 +155,7 @@ def test_custom_validation_on_nested_gets_run() -> None:
def test_accessing_known_fields_returns_empty_value() -> None: def test_accessing_known_fields_returns_empty_value() -> None:
d = BlogPost() d: Any = BlogPost()
assert [] == d.authors assert [] == d.authors
@@ -162,7 +165,7 @@ def test_accessing_known_fields_returns_empty_value() -> None:
def test_empty_values_are_not_serialized() -> None: def test_empty_values_are_not_serialized() -> None:
d = BlogPost( d: Any = BlogPost(
authors=[{"name": "Guian", "email": "[email protected]"}], created=None authors=[{"name": "Guian", "email": "[email protected]"}], created=None
) )
+11 -10
View File
@@ -26,13 +26,14 @@
# under the License. # under the License.
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Any
import pytest import pytest
from opensearchpy import Range from opensearchpy import Range
@pytest.mark.parametrize( @pytest.mark.parametrize( # type: ignore
"kwargs, item", "kwargs, item",
[ [
({}, 1), ({}, 1),
@@ -44,11 +45,11 @@ from opensearchpy import Range
({"gt": datetime.now() - timedelta(seconds=10)}, datetime.now()), ({"gt": datetime.now() - timedelta(seconds=10)}, datetime.now()),
], ],
) )
def test_range_contains(kwargs, item) -> None: def test_range_contains(kwargs: Any, item: Any) -> None:
assert item in Range(**kwargs) assert item in Range(**kwargs)
@pytest.mark.parametrize( @pytest.mark.parametrize( # type: ignore
"kwargs, item", "kwargs, item",
[ [
({"gt": -1}, -1), ({"gt": -1}, -1),
@@ -58,11 +59,11 @@ def test_range_contains(kwargs, item) -> None:
({"lte": datetime.now() - timedelta(seconds=10)}, datetime.now()), ({"lte": datetime.now() - timedelta(seconds=10)}, datetime.now()),
], ],
) )
def test_range_not_contains(kwargs, item): def test_range_not_contains(kwargs: Any, item: Any) -> None:
assert item not in Range(**kwargs) assert item not in Range(**kwargs)
@pytest.mark.parametrize( @pytest.mark.parametrize( # type: ignore
"args,kwargs", "args,kwargs",
[ [
(({},), {"lt": 42}), (({},), {"lt": 42}),
@@ -72,12 +73,12 @@ def test_range_not_contains(kwargs, item):
((), {"gt": 1, "gte": 1}), ((), {"gt": 1, "gte": 1}),
], ],
) )
def test_range_raises_value_error_on_wrong_params(args, kwargs) -> None: def test_range_raises_value_error_on_wrong_params(args: Any, kwargs: Any) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Range(*args, **kwargs) Range(*args, **kwargs)
@pytest.mark.parametrize( @pytest.mark.parametrize( # type: ignore
"range,lower,inclusive", "range,lower,inclusive",
[ [
(Range(gt=1), 1, False), (Range(gt=1), 1, False),
@@ -86,11 +87,11 @@ def test_range_raises_value_error_on_wrong_params(args, kwargs) -> None:
(Range(lt=42), None, False), (Range(lt=42), None, False),
], ],
) )
def test_range_lower(range, lower, inclusive) -> None: def test_range_lower(range: Any, lower: Any, inclusive: Any) -> None:
assert (lower, inclusive) == range.lower assert (lower, inclusive) == range.lower
@pytest.mark.parametrize( @pytest.mark.parametrize( # type: ignore
"range,upper,inclusive", "range,upper,inclusive",
[ [
(Range(lt=1), 1, False), (Range(lt=1), 1, False),
@@ -99,5 +100,5 @@ def test_range_lower(range, lower, inclusive) -> None:
(Range(gt=42), None, False), (Range(gt=42), None, False),
], ],
) )
def test_range_upper(range, upper, inclusive) -> None: def test_range_upper(range: Any, upper: Any, inclusive: Any) -> None:
assert (upper, inclusive) == range.upper assert (upper, inclusive) == range.upper
+2 -1
View File
@@ -30,6 +30,7 @@ import sys
import uuid import uuid
from datetime import datetime from datetime import datetime
from decimal import Decimal from decimal import Decimal
from typing import Any
try: try:
import numpy as np import numpy as np
@@ -212,7 +213,7 @@ class TestTextSerializer(TestCase):
class TestDeserializer(TestCase): class TestDeserializer(TestCase):
def setup_method(self, _) -> None: def setup_method(self, _: Any) -> None:
self.de = Deserializer(DEFAULT_SERIALIZERS) self.de = Deserializer(DEFAULT_SERIALIZERS)
def test_deserializes_json_by_default(self) -> None: def test_deserializes_json_by_default(self) -> None:
+3 -2
View File
@@ -26,6 +26,7 @@
# under the License. # under the License.
from typing import Any
from unittest import SkipTest from unittest import SkipTest
from opensearchpy.helpers import test from opensearchpy.helpers import test
@@ -34,7 +35,7 @@ from opensearchpy.helpers.test import OpenSearchTestCase as BaseTestCase
client = None client = None
def get_client(**kwargs): def get_client(**kwargs: Any) -> Any:
global client global client
if client is False: if client is False:
raise SkipTest("No client is available") raise SkipTest("No client is available")
@@ -66,5 +67,5 @@ def setup_module() -> None:
class OpenSearchTestCase(BaseTestCase): class OpenSearchTestCase(BaseTestCase):
@staticmethod @staticmethod
def _get_client(**kwargs): def _get_client(**kwargs: Any) -> Any:
return get_client(**kwargs) return get_client(**kwargs)
+7 -6
View File
@@ -28,6 +28,7 @@
import os import os
import time import time
from typing import Any
import pytest import pytest
@@ -40,11 +41,11 @@ from ..utils import wipe_cluster
# Used for # Used for
OPENSEARCH_VERSION = "" OPENSEARCH_VERSION = ""
OPENSEARCH_BUILD_HASH = "" OPENSEARCH_BUILD_HASH = ""
OPENSEARCH_REST_API_TESTS = [] OPENSEARCH_REST_API_TESTS: Any = []
@pytest.fixture(scope="session") @pytest.fixture(scope="session") # type: ignore
def sync_client_factory(): def sync_client_factory() -> Any:
client = None client = None
try: try:
# Configure the client optionally with an HTTP conn class # Configure the client optionally with an HTTP conn class
@@ -63,7 +64,7 @@ def sync_client_factory():
# We do this little dance with the URL to force # We do this little dance with the URL to force
# Requests to respect 'headers: None' within rest API spec tests. # Requests to respect 'headers: None' within rest API spec tests.
client = opensearchpy.OpenSearch( client = opensearchpy.OpenSearch(
OPENSEARCH_URL.replace("elastic:changeme@", ""), **kw OPENSEARCH_URL.replace("elastic:changeme@", ""), **kw # type: ignore
) )
# Wait for the cluster to report a status of 'yellow' # Wait for the cluster to report a status of 'yellow'
@@ -83,8 +84,8 @@ def sync_client_factory():
client.close() client.close()
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
def sync_client(sync_client_factory): def sync_client(sync_client_factory: Any) -> Any:
try: try:
yield sync_client_factory yield sync_client_factory
finally: finally:
@@ -27,10 +27,10 @@
import re import re
from datetime import datetime from datetime import datetime
from typing import Any
from pytest import fixture from pytest import fixture
from opensearchpy.client import OpenSearch
from opensearchpy.connection.connections import add_connection from opensearchpy.connection.connections import add_connection
from opensearchpy.helpers import bulk from opensearchpy.helpers import bulk
from opensearchpy.helpers.test import get_test_client from opensearchpy.helpers.test import get_test_client
@@ -45,32 +45,32 @@ from .test_data import (
from .test_document import Comment, History, PullRequest, User from .test_document import Comment, History, PullRequest, User
@fixture(scope="session") @fixture(scope="session") # type: ignore
def client() -> OpenSearch: def client() -> Any:
client = get_test_client(verify_certs=False, http_auth=("admin", "admin")) client = get_test_client(verify_certs=False, http_auth=("admin", "admin"))
add_connection("default", client) add_connection("default", client)
return client return client
@fixture(scope="session") @fixture(scope="session") # type: ignore
def opensearch_version(client): def opensearch_version(client: Any) -> Any:
info = client.info() info = client.info()
print(info) print(info)
yield tuple( yield tuple(
int(x) int(x)
for x in re.match(r"^([0-9.]+)", info["version"]["number"]).group(1).split(".") for x in re.match(r"^([0-9.]+)", info["version"]["number"]).group(1).split(".") # type: ignore
) )
@fixture @fixture # type: ignore
def write_client(client): def write_client(client: Any) -> Any:
yield client yield client
client.indices.delete("test-*", ignore=404) client.indices.delete("test-*", ignore=404)
client.indices.delete_template("test-template", ignore=404) client.indices.delete_template("test-template", ignore=404)
@fixture(scope="session") @fixture(scope="session") # type: ignore
def data_client(client): def data_client(client: Any) -> Any:
# create mappings # create mappings
create_git_index(client, "git") create_git_index(client, "git")
create_flat_git_index(client, "flat-git") create_flat_git_index(client, "flat-git")
@@ -82,8 +82,8 @@ def data_client(client):
client.indices.delete("flat-git", ignore=404) client.indices.delete("flat-git", ignore=404)
@fixture @fixture # type: ignore
def pull_request(write_client): def pull_request(write_client: Any) -> Any:
PullRequest.init() PullRequest.init()
pr = PullRequest( pr = PullRequest(
_id=42, _id=42,
@@ -106,8 +106,8 @@ def pull_request(write_client):
return pr return pr
@fixture @fixture # type: ignore
def setup_ubq_tests(client) -> str: def setup_ubq_tests(client: Any) -> str:
index = "test-git" index = "test-git"
create_git_index(client, index) create_git_index(client, index)
bulk(client, TEST_GIT_DATA, raise_on_error=True, refresh=True) bulk(client, TEST_GIT_DATA, raise_on_error=True, refresh=True)
@@ -26,7 +26,7 @@
# under the License. # under the License.
from typing import Tuple from typing import Any
from mock import patch from mock import patch
@@ -40,9 +40,9 @@ from .. import OpenSearchTestCase
class FailingBulkClient(object): class FailingBulkClient(object):
def __init__( def __init__(
self, self,
client, client: Any,
fail_at: Tuple[int] = (2,), fail_at: Any = (2,),
fail_with=TransportError(599, "Error!", {}), fail_with: Any = TransportError(599, "Error!", {}),
) -> None: ) -> None:
self.client = client self.client = client
self._called = 0 self._called = 0
@@ -50,7 +50,7 @@ class FailingBulkClient(object):
self.transport = client.transport self.transport = client.transport
self._fail_with = fail_with self._fail_with = fail_with
def bulk(self, *args, **kwargs): def bulk(self, *args: Any, **kwargs: Any) -> Any:
self._called += 1 self._called += 1
if self._called in self._fail_at: if self._called in self._fail_at:
raise self._fail_with raise self._fail_with
@@ -98,7 +98,7 @@ class TestStreamingBulk(OpenSearchTestCase):
else: else:
assert False, "exception should have been raised" assert False, "exception should have been raised"
def test_different_op_types(self): def test_different_op_types(self) -> Any:
if self.opensearch_version() < (0, 90, 1): if self.opensearch_version() < (0, 90, 1):
raise SkipTest("update supported since 0.90.1") raise SkipTest("update supported since 0.90.1")
self.client.index(index="i", id=45, body={}) self.client.index(index="i", id=45, body={})
@@ -218,7 +218,7 @@ class TestStreamingBulk(OpenSearchTestCase):
fail_with=TransportError(429, "Rejected!", {}), fail_with=TransportError(429, "Rejected!", {}),
) )
def streaming_bulk(): def streaming_bulk() -> Any:
results = list( results = list(
helpers.streaming_bulk( helpers.streaming_bulk(
failing_client, failing_client,
@@ -271,7 +271,7 @@ class TestBulk(OpenSearchTestCase):
self.assertEqual(0, failed) self.assertEqual(0, failed)
self.assertEqual(100, self.client.count(index="test-index")["count"]) self.assertEqual(100, self.client.count(index="test-index")["count"])
def test_errors_are_reported_correctly(self): def test_errors_are_reported_correctly(self) -> None:
self.client.indices.create( self.client.indices.create(
"i", "i",
{ {
@@ -316,7 +316,7 @@ class TestBulk(OpenSearchTestCase):
index="i", index="i",
) )
def test_ignore_error_if_raised(self): def test_ignore_error_if_raised(self) -> None:
# ignore the status code 400 in tuple # ignore the status code 400 in tuple
helpers.bulk( helpers.bulk(
self.client, [{"a": 42}, {"a": "c"}], index="i", ignore_status=(400,) self.client, [{"a": 42}, {"a": "c"}], index="i", ignore_status=(400,)
@@ -349,7 +349,7 @@ class TestBulk(OpenSearchTestCase):
failing_client = FailingBulkClient(self.client) failing_client = FailingBulkClient(self.client)
helpers.bulk(failing_client, [{"a": 42}], index="i", ignore_status=(599,)) helpers.bulk(failing_client, [{"a": 42}], index="i", ignore_status=(599,))
def test_errors_are_collected_properly(self): def test_errors_are_collected_properly(self) -> None:
self.client.indices.create( self.client.indices.create(
"i", "i",
{ {
@@ -384,12 +384,12 @@ class TestScan(OpenSearchTestCase):
}, },
] ]
def teardown_method(self, m) -> None: def teardown_method(self, m: Any) -> None:
self.client.transport.perform_request("DELETE", "/_search/scroll/_all") self.client.transport.perform_request("DELETE", "/_search/scroll/_all")
super(TestScan, self).teardown_method(m) super(TestScan, self).teardown_method(m)
def test_order_can_be_preserved(self): def test_order_can_be_preserved(self) -> None:
bulk = [] bulk: Any = []
for x in range(100): for x in range(100):
bulk.append({"index": {"_index": "test_index", "_id": x}}) bulk.append({"index": {"_index": "test_index", "_id": x}})
bulk.append({"answer": x, "correct": x == 42}) bulk.append({"answer": x, "correct": x == 42})
@@ -408,8 +408,8 @@ class TestScan(OpenSearchTestCase):
self.assertEqual(list(map(str, range(100))), list(d["_id"] for d in docs)) self.assertEqual(list(map(str, range(100))), list(d["_id"] for d in docs))
self.assertEqual(list(range(100)), list(d["_source"]["answer"] for d in docs)) self.assertEqual(list(range(100)), list(d["_source"]["answer"] for d in docs))
def test_all_documents_are_read(self): def test_all_documents_are_read(self) -> None:
bulk = [] bulk: Any = []
for x in range(100): for x in range(100):
bulk.append({"index": {"_index": "test_index", "_id": x}}) bulk.append({"index": {"_index": "test_index", "_id": x}})
bulk.append({"answer": x, "correct": x == 42}) bulk.append({"answer": x, "correct": x == 42})
@@ -421,8 +421,8 @@ class TestScan(OpenSearchTestCase):
self.assertEqual(set(map(str, range(100))), set(d["_id"] for d in docs)) self.assertEqual(set(map(str, range(100))), set(d["_id"] for d in docs))
self.assertEqual(set(range(100)), set(d["_source"]["answer"] for d in docs)) self.assertEqual(set(range(100)), set(d["_source"]["answer"] for d in docs))
def test_scroll_error(self): def test_scroll_error(self) -> None:
bulk = [] bulk: Any = []
for x in range(4): for x in range(4):
bulk.append({"index": {"_index": "test_index"}}) bulk.append({"index": {"_index": "test_index"}})
bulk.append({"value": x}) bulk.append({"value": x})
@@ -456,7 +456,7 @@ class TestScan(OpenSearchTestCase):
self.assertEqual(len(data), 3) self.assertEqual(len(data), 3)
self.assertEqual(data[-1], {"scroll_data": 42}) self.assertEqual(data[-1], {"scroll_data": 42})
def test_initial_search_error(self): def test_initial_search_error(self) -> None:
with patch.object(self, "client") as client_mock: with patch.object(self, "client") as client_mock:
client_mock.search.return_value = { client_mock.search.return_value = {
"_scroll_id": "dummy_id", "_scroll_id": "dummy_id",
@@ -491,7 +491,7 @@ class TestScan(OpenSearchTestCase):
client_mock.scroll.assert_not_called() client_mock.scroll.assert_not_called()
client_mock.clear_scroll.assert_not_called() client_mock.clear_scroll.assert_not_called()
def test_scan_auth_kwargs_forwarded(self): def test_scan_auth_kwargs_forwarded(self) -> None:
for key, val in { for key, val in {
"api_key": ("name", "value"), "api_key": ("name", "value"),
"http_auth": ("username", "password"), "http_auth": ("username", "password"),
@@ -510,7 +510,7 @@ class TestScan(OpenSearchTestCase):
} }
client_mock.clear_scroll.return_value = {} client_mock.clear_scroll.return_value = {}
data = list(helpers.scan(self.client, index="test_index", **{key: val})) data = list(helpers.scan(self.client, index="test_index", **{key: val})) # type: ignore
self.assertEqual(data, [{"search_data": 1}]) self.assertEqual(data, [{"search_data": 1}])
@@ -523,7 +523,7 @@ class TestScan(OpenSearchTestCase):
): ):
self.assertEqual(api_mock.call_args[1][key], val) self.assertEqual(api_mock.call_args[1][key], val)
def test_scan_auth_kwargs_favor_scroll_kwargs_option(self): def test_scan_auth_kwargs_favor_scroll_kwargs_option(self) -> None:
with patch.object(self, "client") as client_mock: with patch.object(self, "client") as client_mock:
client_mock.search.return_value = { client_mock.search.return_value = {
"_scroll_id": "scroll_id", "_scroll_id": "scroll_id",
@@ -555,8 +555,8 @@ class TestScan(OpenSearchTestCase):
self.assertEqual(client_mock.scroll.call_args[1]["sort"], "asc") self.assertEqual(client_mock.scroll.call_args[1]["sort"], "asc")
@patch("opensearchpy.helpers.actions.logger") @patch("opensearchpy.helpers.actions.logger")
def test_logger(self, logger_mock): def test_logger(self, logger_mock: Any) -> None:
bulk = [] bulk: Any = []
for x in range(4): for x in range(4):
bulk.append({"index": {"_index": "test_index"}}) bulk.append({"index": {"_index": "test_index"}})
bulk.append({"value": x}) bulk.append({"value": x})
@@ -590,8 +590,8 @@ class TestScan(OpenSearchTestCase):
pass pass
logger_mock.warning.assert_called() logger_mock.warning.assert_called()
def test_clear_scroll(self): def test_clear_scroll(self) -> None:
bulk = [] bulk: Any = []
for x in range(4): for x in range(4):
bulk.append({"index": {"_index": "test_index"}}) bulk.append({"index": {"_index": "test_index"}})
bulk.append({"value": x}) bulk.append({"value": x})
@@ -617,7 +617,7 @@ class TestScan(OpenSearchTestCase):
) )
spy.assert_not_called() spy.assert_not_called()
def test_shards_no_skipped_field(self): def test_shards_no_skipped_field(self) -> None:
with patch.object(self, "client") as client_mock: with patch.object(self, "client") as client_mock:
client_mock.search.return_value = { client_mock.search.return_value = {
"_scroll_id": "dummy_id", "_scroll_id": "dummy_id",
@@ -646,8 +646,8 @@ class TestScan(OpenSearchTestCase):
class TestReindex(OpenSearchTestCase): class TestReindex(OpenSearchTestCase):
def setup_method(self, _): def setup_method(self, _: Any) -> None:
bulk = [] bulk: Any = []
for x in range(100): for x in range(100):
bulk.append({"index": {"_index": "test_index", "_id": x}}) bulk.append({"index": {"_index": "test_index", "_id": x}})
bulk.append( bulk.append(
@@ -716,7 +716,7 @@ class TestReindex(OpenSearchTestCase):
class TestParentChildReindex(OpenSearchTestCase): class TestParentChildReindex(OpenSearchTestCase):
def setup_method(self, _): def setup_method(self, _: Any) -> None:
body = { body = {
"settings": {"number_of_shards": 1, "number_of_replicas": 0}, "settings": {"number_of_shards": 1, "number_of_replicas": 0},
"mappings": { "mappings": {
@@ -25,10 +25,12 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
from typing import Any
from opensearchpy import analyzer, token_filter, tokenizer from opensearchpy import analyzer, token_filter, tokenizer
def test_simulate_with_just__builtin_tokenizer(client) -> None: def test_simulate_with_just__builtin_tokenizer(client: Any) -> None:
a = analyzer("my-analyzer", tokenizer="keyword") a = analyzer("my-analyzer", tokenizer="keyword")
tokens = a.simulate("Hello World!", using=client).tokens tokens = a.simulate("Hello World!", using=client).tokens
@@ -36,7 +38,7 @@ def test_simulate_with_just__builtin_tokenizer(client) -> None:
assert tokens[0].token == "Hello World!" assert tokens[0].token == "Hello World!"
def test_simulate_complex(client) -> None: def test_simulate_complex(client: Any) -> None:
a = analyzer( a = analyzer(
"my-analyzer", "my-analyzer",
tokenizer=tokenizer("split_words", "simple_pattern_split", pattern=":"), tokenizer=tokenizer("split_words", "simple_pattern_split", pattern=":"),
@@ -49,7 +51,7 @@ def test_simulate_complex(client) -> None:
assert ["this", "works"] == [t.token for t in tokens] assert ["this", "works"] == [t.token for t in tokens]
def test_simulate_builtin(client) -> None: def test_simulate_builtin(client: Any) -> None:
a = analyzer("my-analyzer", "english") a = analyzer("my-analyzer", "english")
tokens = a.simulate("fixes running").tokens tokens = a.simulate("fixes running").tokens
@@ -25,15 +25,17 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
from typing import Any
from opensearchpy.helpers.search import Q, Search from opensearchpy.helpers.search import Q, Search
def test_count_all(data_client) -> None: def test_count_all(data_client: Any) -> None:
s = Search(using=data_client).index("git") s = Search(using=data_client).index("git")
assert 53 == s.count() assert 53 == s.count()
def test_count_prefetch(data_client, mocker) -> None: def test_count_prefetch(data_client: Any, mocker: Any) -> None:
mocker.spy(data_client, "count") mocker.spy(data_client, "count")
search = Search(using=data_client).index("git") search = Search(using=data_client).index("git")
@@ -46,7 +48,7 @@ def test_count_prefetch(data_client, mocker) -> None:
assert data_client.count.call_count == 1 assert data_client.count.call_count == 1
def test_count_filter(data_client) -> None: def test_count_filter(data_client: Any) -> None:
s = Search(using=data_client).index("git").filter(~Q("exists", field="parent_shas")) s = Search(using=data_client).index("git").filter(~Q("exists", field="parent_shas"))
# initial commit + repo document # initial commit + repo document
assert 2 == s.count() assert 2 == s.count()
@@ -30,7 +30,7 @@ from __future__ import unicode_literals
from typing import Any, Dict from typing import Any, Dict
def create_flat_git_index(client, index): def create_flat_git_index(client: Any, index: Any) -> None:
# we will use user on several places # we will use user on several places
user_mapping = { user_mapping = {
"properties": {"name": {"type": "text", "fields": {"raw": {"type": "keyword"}}}} "properties": {"name": {"type": "text", "fields": {"raw": {"type": "keyword"}}}}
@@ -73,7 +73,7 @@ def create_flat_git_index(client, index):
) )
def create_git_index(client, index): def create_git_index(client: Any, index: Any) -> None:
# we will use user on several places # we will use user on several places
user_mapping = { user_mapping = {
"properties": {"name": {"type": "text", "fields": {"raw": {"type": "keyword"}}}} "properties": {"name": {"type": "text", "fields": {"raw": {"type": "keyword"}}}}
@@ -1095,7 +1095,7 @@ DATA = [
] ]
def flatten_doc(d) -> Dict[str, Any]: def flatten_doc(d: Any) -> Dict[str, Any]:
src = d["_source"].copy() src = d["_source"].copy()
del src["commit_repo"] del src["commit_repo"]
return {"_index": "flat-git", "_id": d["_id"], "_source": src} return {"_index": "flat-git", "_id": d["_id"], "_source": src}
@@ -1104,7 +1104,7 @@ def flatten_doc(d) -> Dict[str, Any]:
FLAT_DATA = [flatten_doc(d) for d in DATA if "routing" in d] FLAT_DATA = [flatten_doc(d) for d in DATA if "routing" in d]
def create_test_git_data(d) -> Dict[str, Any]: def create_test_git_data(d: Any) -> Dict[str, Any]:
src = d["_source"].copy() src = d["_source"].copy()
return { return {
"_index": "test-git", "_index": "test-git",
@@ -27,6 +27,7 @@
from datetime import datetime from datetime import datetime
from ipaddress import ip_address from ipaddress import ip_address
from typing import Any
import pytest import pytest
from pytest import raises from pytest import raises
@@ -78,7 +79,7 @@ class Repository(Document):
tags = Keyword() tags = Keyword()
@classmethod @classmethod
def search(cls): def search(cls, using: Any = None, index: Any = None) -> Any:
return super(Repository, cls).search().filter("term", commit_repo="repo") return super(Repository, cls).search().filter("term", commit_repo="repo")
class Index: class Index:
@@ -131,7 +132,7 @@ class SerializationDoc(Document):
name = "test-serialization" name = "test-serialization"
def test_serialization(write_client): def test_serialization(write_client: Any) -> None:
SerializationDoc.init() SerializationDoc.init()
write_client.index( write_client.index(
index="test-serialization", index="test-serialization",
@@ -161,7 +162,7 @@ def test_serialization(write_client):
} }
def test_nested_inner_hits_are_wrapped_properly(pull_request) -> None: def test_nested_inner_hits_are_wrapped_properly(pull_request: Any) -> None:
history_query = Q( history_query = Q(
"nested", "nested",
path="comments.history", path="comments.history",
@@ -189,7 +190,7 @@ def test_nested_inner_hits_are_wrapped_properly(pull_request) -> None:
assert "score" in history.meta assert "score" in history.meta
def test_nested_inner_hits_are_deserialized_properly(pull_request) -> None: def test_nested_inner_hits_are_deserialized_properly(pull_request: Any) -> None:
s = PullRequest.search().query( s = PullRequest.search().query(
"nested", "nested",
inner_hits={}, inner_hits={},
@@ -204,7 +205,7 @@ def test_nested_inner_hits_are_deserialized_properly(pull_request) -> None:
assert isinstance(pr.comments[0].created_at, datetime) assert isinstance(pr.comments[0].created_at, datetime)
def test_nested_top_hits_are_wrapped_properly(pull_request) -> None: def test_nested_top_hits_are_wrapped_properly(pull_request: Any) -> None:
s = PullRequest.search() s = PullRequest.search()
s.aggs.bucket("comments", "nested", path="comments").metric( s.aggs.bucket("comments", "nested", path="comments").metric(
"hits", "top_hits", size=1 "hits", "top_hits", size=1
@@ -216,7 +217,7 @@ def test_nested_top_hits_are_wrapped_properly(pull_request) -> None:
assert isinstance(r.aggregations.comments.hits.hits[0], Comment) assert isinstance(r.aggregations.comments.hits.hits[0], Comment)
def test_update_object_field(write_client) -> None: def test_update_object_field(write_client: Any) -> None:
Wiki.init() Wiki.init()
w = Wiki( w = Wiki(
owner=User(name="Honza Kral"), owner=User(name="Honza Kral"),
@@ -236,7 +237,7 @@ def test_update_object_field(write_client) -> None:
assert w.ranked == {"test1": 0.1, "topic2": 0.2} assert w.ranked == {"test1": 0.1, "topic2": 0.2}
def test_update_script(write_client) -> None: def test_update_script(write_client: Any) -> None:
Wiki.init() Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42) w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
w.save() w.save()
@@ -246,7 +247,7 @@ def test_update_script(write_client) -> None:
assert w.views == 47 assert w.views == 47
def test_update_retry_on_conflict(write_client) -> None: def test_update_retry_on_conflict(write_client: Any) -> None:
Wiki.init() Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42) w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
w.save() w.save()
@@ -260,8 +261,8 @@ def test_update_retry_on_conflict(write_client) -> None:
assert w.views == 52 assert w.views == 52
@pytest.mark.parametrize("retry_on_conflict", [None, 0]) @pytest.mark.parametrize("retry_on_conflict", [None, 0]) # type: ignore
def test_update_conflicting_version(write_client, retry_on_conflict) -> None: def test_update_conflicting_version(write_client: Any, retry_on_conflict: Any) -> None:
Wiki.init() Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42) w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
w.save() w.save()
@@ -278,7 +279,7 @@ def test_update_conflicting_version(write_client, retry_on_conflict) -> None:
) )
def test_save_and_update_return_doc_meta(write_client) -> None: def test_save_and_update_return_doc_meta(write_client: Any) -> None:
Wiki.init() Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42) w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
resp = w.save(return_doc_meta=True) resp = w.save(return_doc_meta=True)
@@ -302,31 +303,33 @@ def test_save_and_update_return_doc_meta(write_client) -> None:
assert resp.keys().__contains__("_version") assert resp.keys().__contains__("_version")
def test_init(write_client) -> None: def test_init(write_client: Any) -> None:
Repository.init(index="test-git") Repository.init(index="test-git")
assert write_client.indices.exists(index="test-git") assert write_client.indices.exists(index="test-git")
def test_get_raises_404_on_index_missing(data_client) -> None: def test_get_raises_404_on_index_missing(data_client: Any) -> None:
with raises(NotFoundError): with raises(NotFoundError):
Repository.get("opensearch-dsl-php", index="not-there") Repository.get("opensearch-dsl-php", index="not-there")
def test_get_raises_404_on_non_existent_id(data_client) -> None: def test_get_raises_404_on_non_existent_id(data_client: Any) -> None:
with raises(NotFoundError): with raises(NotFoundError):
Repository.get("opensearch-dsl-php") Repository.get("opensearch-dsl-php")
def test_get_returns_none_if_404_ignored(data_client) -> None: def test_get_returns_none_if_404_ignored(data_client: Any) -> None:
assert None is Repository.get("opensearch-dsl-php", ignore=404) assert None is Repository.get("opensearch-dsl-php", ignore=404)
def test_get_returns_none_if_404_ignored_and_index_doesnt_exist(data_client) -> None: def test_get_returns_none_if_404_ignored_and_index_doesnt_exist(
data_client: Any,
) -> None:
assert None is Repository.get("42", index="not-there", ignore=404) assert None is Repository.get("42", index="not-there", ignore=404)
def test_get(data_client) -> None: def test_get(data_client: Any) -> None:
opensearch_repo = Repository.get("opensearch-py") opensearch_repo = Repository.get("opensearch-py")
assert isinstance(opensearch_repo, Repository) assert isinstance(opensearch_repo, Repository)
@@ -334,15 +337,15 @@ def test_get(data_client) -> None:
assert datetime(2014, 3, 3) == opensearch_repo.created_at assert datetime(2014, 3, 3) == opensearch_repo.created_at
def test_exists_return_true(data_client) -> None: def test_exists_return_true(data_client: Any) -> None:
assert Repository.exists("opensearch-py") assert Repository.exists("opensearch-py")
def test_exists_false(data_client) -> None: def test_exists_false(data_client: Any) -> None:
assert not Repository.exists("opensearch-dsl-php") assert not Repository.exists("opensearch-dsl-php")
def test_get_with_tz_date(data_client) -> None: def test_get_with_tz_date(data_client: Any) -> None:
first_commit = Commit.get( first_commit = Commit.get(
id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py" id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py"
) )
@@ -354,7 +357,7 @@ def test_get_with_tz_date(data_client) -> None:
) )
def test_save_with_tz_date(data_client) -> None: def test_save_with_tz_date(data_client: Any) -> None:
tzinfo = timezone("Europe/Prague") tzinfo = timezone("Europe/Prague")
first_commit = Commit.get( first_commit = Commit.get(
id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py" id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py"
@@ -381,7 +384,7 @@ COMMIT_DOCS_WITH_MISSING = [
] ]
def test_mget(data_client) -> None: def test_mget(data_client: Any) -> None:
commits = Commit.mget(COMMIT_DOCS_WITH_MISSING) commits = Commit.mget(COMMIT_DOCS_WITH_MISSING)
assert commits[0] is None assert commits[0] is None
assert commits[1].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037" assert commits[1].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037"
@@ -389,23 +392,23 @@ def test_mget(data_client) -> None:
assert commits[3].meta.id == "eb3e543323f189fd7b698e66295427204fff5755" assert commits[3].meta.id == "eb3e543323f189fd7b698e66295427204fff5755"
def test_mget_raises_exception_when_missing_param_is_invalid(data_client) -> None: def test_mget_raises_exception_when_missing_param_is_invalid(data_client: Any) -> None:
with raises(ValueError): with raises(ValueError):
Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raj") Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raj")
def test_mget_raises_404_when_missing_param_is_raise(data_client) -> None: def test_mget_raises_404_when_missing_param_is_raise(data_client: Any) -> None:
with raises(NotFoundError): with raises(NotFoundError):
Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raise") Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raise")
def test_mget_ignores_missing_docs_when_missing_param_is_skip(data_client) -> None: def test_mget_ignores_missing_docs_when_missing_param_is_skip(data_client: Any) -> None:
commits = Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="skip") commits = Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="skip")
assert commits[0].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037" assert commits[0].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037"
assert commits[1].meta.id == "eb3e543323f189fd7b698e66295427204fff5755" assert commits[1].meta.id == "eb3e543323f189fd7b698e66295427204fff5755"
def test_update_works_from_search_response(data_client) -> None: def test_update_works_from_search_response(data_client: Any) -> None:
opensearch_repo = Repository.search().execute()[0] opensearch_repo = Repository.search().execute()[0]
opensearch_repo.update(owner={"other_name": "opensearchpy"}) opensearch_repo.update(owner={"other_name": "opensearchpy"})
@@ -416,7 +419,7 @@ def test_update_works_from_search_response(data_client) -> None:
assert "opensearch" == new_version.owner.name assert "opensearch" == new_version.owner.name
def test_update(data_client) -> None: def test_update(data_client: Any) -> None:
opensearch_repo = Repository.get("opensearch-py") opensearch_repo = Repository.get("opensearch-py")
v = opensearch_repo.meta.version v = opensearch_repo.meta.version
@@ -440,7 +443,7 @@ def test_update(data_client) -> None:
assert "primary_term" in new_version.meta assert "primary_term" in new_version.meta
def test_save_updates_existing_doc(data_client) -> None: def test_save_updates_existing_doc(data_client: Any) -> None:
opensearch_repo = Repository.get("opensearch-py") opensearch_repo = Repository.get("opensearch-py")
opensearch_repo.new_field = "testing-save" opensearch_repo.new_field = "testing-save"
@@ -453,7 +456,7 @@ def test_save_updates_existing_doc(data_client) -> None:
assert new_repo["_seq_no"] == opensearch_repo.meta.seq_no assert new_repo["_seq_no"] == opensearch_repo.meta.seq_no
def test_save_automatically_uses_seq_no_and_primary_term(data_client) -> None: def test_save_automatically_uses_seq_no_and_primary_term(data_client: Any) -> None:
opensearch_repo = Repository.get("opensearch-py") opensearch_repo = Repository.get("opensearch-py")
opensearch_repo.meta.seq_no += 1 opensearch_repo.meta.seq_no += 1
@@ -461,7 +464,7 @@ def test_save_automatically_uses_seq_no_and_primary_term(data_client) -> None:
opensearch_repo.save() opensearch_repo.save()
def test_delete_automatically_uses_seq_no_and_primary_term(data_client) -> None: def test_delete_automatically_uses_seq_no_and_primary_term(data_client: Any) -> None:
opensearch_repo = Repository.get("opensearch-py") opensearch_repo = Repository.get("opensearch-py")
opensearch_repo.meta.seq_no += 1 opensearch_repo.meta.seq_no += 1
@@ -469,13 +472,13 @@ def test_delete_automatically_uses_seq_no_and_primary_term(data_client) -> None:
opensearch_repo.delete() opensearch_repo.delete()
def assert_doc_equals(expected, actual) -> None: def assert_doc_equals(expected: Any, actual: Any) -> None:
for f in expected: for f in expected:
assert f in actual assert f in actual
assert actual[f] == expected[f] assert actual[f] == expected[f]
def test_can_save_to_different_index(write_client): def test_can_save_to_different_index(write_client: Any) -> None:
test_repo = Repository(description="testing", meta={"id": 42}) test_repo = Repository(description="testing", meta={"id": 42})
assert test_repo.save(index="test-document") assert test_repo.save(index="test-document")
@@ -490,7 +493,7 @@ def test_can_save_to_different_index(write_client):
) )
def test_save_without_skip_empty_will_include_empty_fields(write_client) -> None: def test_save_without_skip_empty_will_include_empty_fields(write_client: Any) -> None:
test_repo = Repository(field_1=[], field_2=None, field_3={}, meta={"id": 42}) test_repo = Repository(field_1=[], field_2=None, field_3={}, meta={"id": 42})
assert test_repo.save(index="test-document", skip_empty=False) assert test_repo.save(index="test-document", skip_empty=False)
@@ -505,7 +508,7 @@ def test_save_without_skip_empty_will_include_empty_fields(write_client) -> None
) )
def test_delete(write_client) -> None: def test_delete(write_client: Any) -> None:
write_client.create( write_client.create(
index="test-document", index="test-document",
id="opensearch-py", id="opensearch-py",
@@ -526,11 +529,11 @@ def test_delete(write_client) -> None:
) )
def test_search(data_client) -> None: def test_search(data_client: Any) -> None:
assert Repository.search().count() == 1 assert Repository.search().count() == 1
def test_search_returns_proper_doc_classes(data_client) -> None: def test_search_returns_proper_doc_classes(data_client: Any) -> None:
result = Repository.search().execute() result = Repository.search().execute()
opensearch_repo = result.hits[0] opensearch_repo = result.hits[0]
@@ -539,11 +542,13 @@ def test_search_returns_proper_doc_classes(data_client) -> None:
assert opensearch_repo.owner.name == "opensearch" assert opensearch_repo.owner.name == "opensearch"
def test_refresh_mapping(data_client) -> None: def test_refresh_mapping(data_client: Any) -> None:
class Commit(Document): class Commit(Document):
class Index: class Index:
name = "git" name = "git"
_index: Any
Commit._index.load_mappings() Commit._index.load_mappings()
assert "stats" in Commit._index._mapping assert "stats" in Commit._index._mapping
@@ -553,7 +558,7 @@ def test_refresh_mapping(data_client) -> None:
assert isinstance(Commit._index._mapping["committed_date"], Date) assert isinstance(Commit._index._mapping["committed_date"], Date)
def test_highlight_in_meta(data_client) -> None: def test_highlight_in_meta(data_client: Any) -> None:
commit = ( commit = (
Commit.search() Commit.search()
.query("match", description="inverting") .query("match", description="inverting")
@@ -26,6 +26,7 @@
# under the License. # under the License.
from datetime import datetime from datetime import datetime
from typing import Any
import pytest import pytest
@@ -66,8 +67,8 @@ class MetricSearch(FacetedSearch):
} }
@pytest.fixture(scope="session") @pytest.fixture(scope="session") # type: ignore
def commit_search_cls(opensearch_version): def commit_search_cls(opensearch_version: Any) -> Any:
interval_kwargs = {"fixed_interval": "1d"} interval_kwargs = {"fixed_interval": "1d"}
class CommitSearch(FacetedSearch): class CommitSearch(FacetedSearch):
@@ -91,8 +92,8 @@ def commit_search_cls(opensearch_version):
return CommitSearch return CommitSearch
@pytest.fixture(scope="session") @pytest.fixture(scope="session") # type: ignore
def repo_search_cls(opensearch_version): def repo_search_cls(opensearch_version: Any) -> Any:
interval_type = "calendar_interval" interval_type = "calendar_interval"
class RepoSearch(FacetedSearch): class RepoSearch(FacetedSearch):
@@ -105,15 +106,15 @@ def repo_search_cls(opensearch_version):
), ),
} }
def search(self): def search(self) -> Any:
s = super(RepoSearch, self).search() s = super(RepoSearch, self).search()
return s.filter("term", commit_repo="repo") return s.filter("term", commit_repo="repo")
return RepoSearch return RepoSearch
@pytest.fixture(scope="session") @pytest.fixture(scope="session") # type: ignore
def pr_search_cls(opensearch_version): def pr_search_cls(opensearch_version: Any) -> Any:
interval_type = "calendar_interval" interval_type = "calendar_interval"
class PRSearch(FacetedSearch): class PRSearch(FacetedSearch):
@@ -131,7 +132,7 @@ def pr_search_cls(opensearch_version):
return PRSearch return PRSearch
def test_facet_with_custom_metric(data_client) -> None: def test_facet_with_custom_metric(data_client: Any) -> None:
ms = MetricSearch() ms = MetricSearch()
r = ms.execute() r = ms.execute()
@@ -140,7 +141,7 @@ def test_facet_with_custom_metric(data_client) -> None:
assert dates[0] == 1399038439000 assert dates[0] == 1399038439000
def test_nested_facet(pull_request, pr_search_cls) -> None: def test_nested_facet(pull_request: Any, pr_search_cls: Any) -> None:
prs = pr_search_cls() prs = pr_search_cls()
r = prs.execute() r = prs.execute()
@@ -148,7 +149,7 @@ def test_nested_facet(pull_request, pr_search_cls) -> None:
assert [(datetime(2018, 1, 1, 0, 0), 1, False)] == r.facets.comments assert [(datetime(2018, 1, 1, 0, 0), 1, False)] == r.facets.comments
def test_nested_facet_with_filter(pull_request, pr_search_cls) -> None: def test_nested_facet_with_filter(pull_request: Any, pr_search_cls: Any) -> None:
prs = pr_search_cls(filters={"comments": datetime(2018, 1, 1, 0, 0)}) prs = pr_search_cls(filters={"comments": datetime(2018, 1, 1, 0, 0)})
r = prs.execute() r = prs.execute()
@@ -160,7 +161,7 @@ def test_nested_facet_with_filter(pull_request, pr_search_cls) -> None:
assert not r.hits assert not r.hits
def test_datehistogram_facet(data_client, repo_search_cls) -> None: def test_datehistogram_facet(data_client: Any, repo_search_cls: Any) -> None:
rs = repo_search_cls() rs = repo_search_cls()
r = rs.execute() r = rs.execute()
@@ -168,7 +169,7 @@ def test_datehistogram_facet(data_client, repo_search_cls) -> None:
assert [(datetime(2014, 3, 1, 0, 0), 1, False)] == r.facets.created assert [(datetime(2014, 3, 1, 0, 0), 1, False)] == r.facets.created
def test_boolean_facet(data_client, repo_search_cls) -> None: def test_boolean_facet(data_client: Any, repo_search_cls: Any) -> None:
rs = repo_search_cls() rs = repo_search_cls()
r = rs.execute() r = rs.execute()
@@ -179,7 +180,7 @@ def test_boolean_facet(data_client, repo_search_cls) -> None:
def test_empty_search_finds_everything( def test_empty_search_finds_everything(
data_client, opensearch_version, commit_search_cls data_client: Any, opensearch_version: Any, commit_search_cls: Any
) -> None: ) -> None:
cs = commit_search_cls() cs = commit_search_cls()
r = cs.execute() r = cs.execute()
@@ -225,7 +226,7 @@ def test_empty_search_finds_everything(
def test_term_filters_are_shown_as_selected_and_data_is_filtered( def test_term_filters_are_shown_as_selected_and_data_is_filtered(
data_client, commit_search_cls data_client: Any, commit_search_cls: Any
) -> None: ) -> None:
cs = commit_search_cls(filters={"files": "test_opensearchpy/test_dsl"}) cs = commit_search_cls(filters={"files": "test_opensearchpy/test_dsl"})
@@ -271,7 +272,7 @@ def test_term_filters_are_shown_as_selected_and_data_is_filtered(
def test_range_filters_are_shown_as_selected_and_data_is_filtered( def test_range_filters_are_shown_as_selected_and_data_is_filtered(
data_client, commit_search_cls data_client: Any, commit_search_cls: Any
) -> None: ) -> None:
cs = commit_search_cls(filters={"deletions": "better"}) cs = commit_search_cls(filters={"deletions": "better"})
@@ -280,7 +281,7 @@ def test_range_filters_are_shown_as_selected_and_data_is_filtered(
assert 19 == r.hits.total.value assert 19 == r.hits.total.value
def test_pagination(data_client, commit_search_cls) -> None: def test_pagination(data_client: Any, commit_search_cls: Any) -> None:
cs = commit_search_cls() cs = commit_search_cls()
cs = cs[0:20] cs = cs[0:20]
@@ -25,6 +25,8 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
from typing import Any
from opensearchpy import Date, Document, Index, IndexTemplate, Text from opensearchpy import Date, Document, Index, IndexTemplate, Text
from opensearchpy.helpers import analysis from opensearchpy.helpers import analysis
@@ -34,7 +36,7 @@ class Post(Document):
published_from = Date() published_from = Date()
def test_index_template_works(write_client) -> None: def test_index_template_works(write_client: Any) -> None:
it = IndexTemplate("test-template", "test-*") it = IndexTemplate("test-template", "test-*")
it.document(Post) it.document(Post)
it.settings(number_of_replicas=0, number_of_shards=1) it.settings(number_of_replicas=0, number_of_shards=1)
@@ -55,7 +57,7 @@ def test_index_template_works(write_client) -> None:
} == write_client.indices.get_mapping(index="test-blog") } == write_client.indices.get_mapping(index="test-blog")
def test_index_can_be_saved_even_with_settings(write_client) -> None: def test_index_can_be_saved_even_with_settings(write_client: Any) -> None:
i = Index("test-blog", using=write_client) i = Index("test-blog", using=write_client)
i.settings(number_of_shards=3, number_of_replicas=0) i.settings(number_of_shards=3, number_of_replicas=0)
i.save() i.save()
@@ -67,12 +69,12 @@ def test_index_can_be_saved_even_with_settings(write_client) -> None:
) )
def test_index_exists(data_client) -> None: def test_index_exists(data_client: Any) -> None:
assert Index("git").exists() assert Index("git").exists()
assert not Index("not-there").exists() assert not Index("not-there").exists()
def test_index_can_be_created_with_settings_and_mappings(write_client) -> None: def test_index_can_be_created_with_settings_and_mappings(write_client: Any) -> None:
i = Index("test-blog", using=write_client) i = Index("test-blog", using=write_client)
i.document(Post) i.document(Post)
i.settings(number_of_replicas=0, number_of_shards=1) i.settings(number_of_replicas=0, number_of_shards=1)
@@ -97,7 +99,7 @@ def test_index_can_be_created_with_settings_and_mappings(write_client) -> None:
} }
def test_delete(write_client) -> None: def test_delete(write_client: Any) -> None:
write_client.indices.create( write_client.indices.create(
index="test-index", index="test-index",
body={"settings": {"number_of_replicas": 0, "number_of_shards": 1}}, body={"settings": {"number_of_replicas": 0, "number_of_shards": 1}},
@@ -108,7 +110,7 @@ def test_delete(write_client) -> None:
assert not write_client.indices.exists(index="test-index") assert not write_client.indices.exists(index="test-index")
def test_multiple_indices_with_same_doc_type_work(write_client) -> None: def test_multiple_indices_with_same_doc_type_work(write_client: Any) -> None:
i1 = Index("test-index-1", using=write_client) i1 = Index("test-index-1", using=write_client)
i2 = Index("test-index-2", using=write_client) i2 = Index("test-index-2", using=write_client)
@@ -116,8 +118,8 @@ def test_multiple_indices_with_same_doc_type_work(write_client) -> None:
i.document(Post) i.document(Post)
i.create() i.create()
for i in ("test-index-1", "test-index-2"): for j in ("test-index-1", "test-index-2"):
settings = write_client.indices.get_settings(index=i) settings = write_client.indices.get_settings(index=j)
assert settings[i]["settings"]["index"]["analysis"] == { assert settings[j]["settings"]["index"]["analysis"] == {
"analyzer": {"my_analyzer": {"type": "custom", "tokenizer": "keyword"}} "analyzer": {"my_analyzer": {"type": "custom", "tokenizer": "keyword"}}
} }
@@ -25,13 +25,15 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
from typing import Any
from pytest import raises from pytest import raises
from opensearchpy import exceptions from opensearchpy import exceptions
from opensearchpy.helpers import analysis, mapping from opensearchpy.helpers import analysis, mapping
def test_mapping_saved_into_opensearch(write_client) -> None: def test_mapping_saved_into_opensearch(write_client: Any) -> None:
m = mapping.Mapping() m = mapping.Mapping()
m.field( m.field(
"name", "text", analyzer=analysis.analyzer("my_analyzer", tokenizer="keyword") "name", "text", analyzer=analysis.analyzer("my_analyzer", tokenizer="keyword")
@@ -52,7 +54,7 @@ def test_mapping_saved_into_opensearch(write_client) -> None:
def test_mapping_saved_into_opensearch_when_index_already_exists_closed( def test_mapping_saved_into_opensearch_when_index_already_exists_closed(
write_client, write_client: Any,
) -> None: ) -> None:
m = mapping.Mapping() m = mapping.Mapping()
m.field( m.field(
@@ -77,7 +79,7 @@ def test_mapping_saved_into_opensearch_when_index_already_exists_closed(
def test_mapping_saved_into_opensearch_when_index_already_exists_with_analysis( def test_mapping_saved_into_opensearch_when_index_already_exists_with_analysis(
write_client, write_client: Any,
) -> None: ) -> None:
m = mapping.Mapping() m = mapping.Mapping()
analyzer = analysis.analyzer("my_analyzer", tokenizer="keyword") analyzer = analysis.analyzer("my_analyzer", tokenizer="keyword")
@@ -107,7 +109,7 @@ def test_mapping_saved_into_opensearch_when_index_already_exists_with_analysis(
} == write_client.indices.get_mapping(index="test-mapping") } == write_client.indices.get_mapping(index="test-mapping")
def test_mapping_gets_updated_from_opensearch(write_client): def test_mapping_gets_updated_from_opensearch(write_client: Any) -> None:
write_client.indices.create( write_client.indices.create(
index="test-mapping", index="test-mapping",
body={ body={
@@ -27,6 +27,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from typing import Any
from pytest import raises from pytest import raises
from opensearchpy import ( from opensearchpy import (
@@ -50,7 +52,7 @@ class Repository(Document):
tags = Keyword() tags = Keyword()
@classmethod @classmethod
def search(cls): def search(cls, using: Any = None, index: Any = None) -> Any:
return super(Repository, cls).search().filter("term", commit_repo="repo") return super(Repository, cls).search().filter("term", commit_repo="repo")
class Index: class Index:
@@ -62,7 +64,7 @@ class Commit(Document):
name = "flat-git" name = "flat-git"
def test_filters_aggregation_buckets_are_accessible(data_client) -> None: def test_filters_aggregation_buckets_are_accessible(data_client: Any) -> None:
has_tests_query = Q("term", files="test_opensearchpy/test_dsl") has_tests_query = Q("term", files="test_opensearchpy/test_dsl")
s = Commit.search()[0:0] s = Commit.search()[0:0]
s.aggs.bucket("top_authors", "terms", field="author.name.raw").bucket( s.aggs.bucket("top_authors", "terms", field="author.name.raw").bucket(
@@ -83,7 +85,7 @@ def test_filters_aggregation_buckets_are_accessible(data_client) -> None:
) )
def test_top_hits_are_wrapped_in_response(data_client) -> None: def test_top_hits_are_wrapped_in_response(data_client: Any) -> None:
s = Commit.search()[0:0] s = Commit.search()[0:0]
s.aggs.bucket("top_authors", "terms", field="author.name.raw").metric( s.aggs.bucket("top_authors", "terms", field="author.name.raw").metric(
"top_commits", "top_hits", size=5 "top_commits", "top_hits", size=5
@@ -99,7 +101,7 @@ def test_top_hits_are_wrapped_in_response(data_client) -> None:
assert isinstance(hits[0], Commit) assert isinstance(hits[0], Commit)
def test_inner_hits_are_wrapped_in_response(data_client) -> None: def test_inner_hits_are_wrapped_in_response(data_client: Any) -> None:
s = Search(index="git")[0:1].query( s = Search(index="git")[0:1].query(
"has_parent", parent_type="repo", inner_hits={}, query=Q("match_all") "has_parent", parent_type="repo", inner_hits={}, query=Q("match_all")
) )
@@ -110,7 +112,7 @@ def test_inner_hits_are_wrapped_in_response(data_client) -> None:
assert repr(commit.meta.inner_hits.repo[0]).startswith("<Hit(git/opensearch-py): ") assert repr(commit.meta.inner_hits.repo[0]).startswith("<Hit(git/opensearch-py): ")
def test_scan_respects_doc_types(data_client) -> None: def test_scan_respects_doc_types(data_client: Any) -> None:
repos = list(Repository.search().scan()) repos = list(Repository.search().scan())
assert 1 == len(repos) assert 1 == len(repos)
@@ -118,7 +120,7 @@ def test_scan_respects_doc_types(data_client) -> None:
assert repos[0].organization == "opensearch" assert repos[0].organization == "opensearch"
def test_scan_iterates_through_all_docs(data_client) -> None: def test_scan_iterates_through_all_docs(data_client: Any) -> None:
s = Search(index="flat-git") s = Search(index="flat-git")
commits = list(s.scan()) commits = list(s.scan())
@@ -127,7 +129,7 @@ def test_scan_iterates_through_all_docs(data_client) -> None:
assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits} assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits}
def test_response_is_cached(data_client) -> None: def test_response_is_cached(data_client: Any) -> None:
s = Repository.search() s = Repository.search()
repos = list(s) repos = list(s)
@@ -135,7 +137,7 @@ def test_response_is_cached(data_client) -> None:
assert s._response.hits == repos assert s._response.hits == repos
def test_multi_search(data_client) -> None: def test_multi_search(data_client: Any) -> None:
s1 = Repository.search() s1 = Repository.search()
s2 = Search(index="flat-git") s2 = Search(index="flat-git")
@@ -152,7 +154,7 @@ def test_multi_search(data_client) -> None:
assert r2._search is s2 assert r2._search is s2
def test_multi_missing(data_client) -> None: def test_multi_missing(data_client: Any) -> None:
s1 = Repository.search() s1 = Repository.search()
s2 = Search(index="flat-git") s2 = Search(index="flat-git")
s3 = Search(index="does_not_exist") s3 = Search(index="does_not_exist")
@@ -175,7 +177,7 @@ def test_multi_missing(data_client) -> None:
assert r3 is None assert r3 is None
def test_raw_subfield_can_be_used_in_aggs(data_client) -> None: def test_raw_subfield_can_be_used_in_aggs(data_client: Any) -> None:
s = Search(index="git")[0:0] s = Search(index="git")[0:0]
s.aggs.bucket("authors", "terms", field="author.name.raw", size=1) s.aggs.bucket("authors", "terms", field="author.name.raw", size=1)
@@ -25,11 +25,13 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
from typing import Any
from opensearchpy.helpers.search import Q from opensearchpy.helpers.search import Q
from opensearchpy.helpers.update_by_query import UpdateByQuery from opensearchpy.helpers.update_by_query import UpdateByQuery
def test_update_by_query_no_script(write_client, setup_ubq_tests) -> None: def test_update_by_query_no_script(write_client: Any, setup_ubq_tests: Any) -> None:
index = setup_ubq_tests index = setup_ubq_tests
ubq = ( ubq = (
@@ -48,7 +50,7 @@ def test_update_by_query_no_script(write_client, setup_ubq_tests) -> None:
assert response.success() assert response.success()
def test_update_by_query_with_script(write_client, setup_ubq_tests) -> None: def test_update_by_query_with_script(write_client: Any, setup_ubq_tests: Any) -> None:
index = setup_ubq_tests index = setup_ubq_tests
ubq = ( ubq = (
@@ -65,7 +67,7 @@ def test_update_by_query_with_script(write_client, setup_ubq_tests) -> None:
assert response.version_conflicts == 0 assert response.version_conflicts == 0
def test_delete_by_query_with_script(write_client, setup_ubq_tests) -> None: def test_delete_by_query_with_script(write_client: Any, setup_ubq_tests: Any) -> None:
index = setup_ubq_tests index = setup_ubq_tests
ubq = ( ubq = (
@@ -23,7 +23,7 @@ class TestAlertingPlugin(OpenSearchTestCase):
(OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)),
"Plugin not supported for opensearch version", "Plugin not supported for opensearch version",
) )
def test_create_destination(self): def test_create_destination(self) -> None:
# Test to create alert destination # Test to create alert destination
dummy_destination = { dummy_destination = {
"name": "my-destination", "name": "my-destination",
@@ -54,7 +54,7 @@ class TestAlertingPlugin(OpenSearchTestCase):
(OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)),
"Plugin not supported for opensearch version", "Plugin not supported for opensearch version",
) )
def test_create_monitor(self): def test_create_monitor(self) -> None:
# Create a dummy destination # Create a dummy destination
self.test_create_destination() self.test_create_destination()
@@ -36,6 +36,7 @@ import os
import re import re
import warnings import warnings
import zipfile import zipfile
from typing import Any
import pytest import pytest
import urllib3 import urllib3
@@ -142,23 +143,23 @@ FALSEY_VALUES = ("", None, False, 0, 0.0)
class YamlRunner: class YamlRunner:
def __init__(self, client) -> None: def __init__(self, client: Any) -> None:
self.client = client self.client = client
self.last_response = None self.last_response: Any = None
self._run_code = None self._run_code: Any = None
self._setup_code = None self._setup_code: Any = None
self._teardown_code = None self._teardown_code: Any = None
self._state = {} self._state: Any = {}
def use_spec(self, test_spec) -> None: def use_spec(self, test_spec: Any) -> None:
self._setup_code = test_spec.pop("setup", None) self._setup_code = test_spec.pop("setup", None)
self._run_code = test_spec.pop("run", None) self._run_code = test_spec.pop("run", None)
self._teardown_code = test_spec.pop("teardown", None) self._teardown_code = test_spec.pop("teardown", None)
def setup(self): def setup(self) -> Any:
# Pull skips from individual tests to not do unnecessary setup. # Pull skips from individual tests to not do unnecessary setup.
skip_code = [] skip_code: Any = []
for action in self._run_code: for action in self._run_code:
assert len(action) == 1 assert len(action) == 1
action_type, _ = list(action.items())[0] action_type, _ = list(action.items())[0]
@@ -174,12 +175,12 @@ class YamlRunner:
if self._setup_code: if self._setup_code:
self.run_code(self._setup_code) self.run_code(self._setup_code)
def teardown(self) -> None: def teardown(self) -> Any:
if self._teardown_code: if self._teardown_code:
self.section("teardown") self.section("teardown")
self.run_code(self._teardown_code) self.run_code(self._teardown_code)
def opensearch_version(self): def opensearch_version(self) -> Any:
global OPENSEARCH_VERSION global OPENSEARCH_VERSION
if OPENSEARCH_VERSION is None: if OPENSEARCH_VERSION is None:
version_string = (self.client.info())["version"]["number"] version_string = (self.client.info())["version"]["number"]
@@ -189,10 +190,10 @@ class YamlRunner:
OPENSEARCH_VERSION = tuple(int(v) if v.isdigit() else 99 for v in version) OPENSEARCH_VERSION = tuple(int(v) if v.isdigit() else 99 for v in version)
return OPENSEARCH_VERSION return OPENSEARCH_VERSION
def section(self, name) -> None: def section(self, name: str) -> None:
print(("=" * 10) + " " + name + " " + ("=" * 10)) print(("=" * 10) + " " + name + " " + ("=" * 10))
def run(self) -> None: def run(self) -> Any:
try: try:
self.setup() self.setup()
self.section("test") self.section("test")
@@ -203,7 +204,7 @@ class YamlRunner:
except Exception: except Exception:
pass pass
def run_code(self, test) -> None: def run_code(self, test: Any) -> Any:
"""Execute an instruction based on its type.""" """Execute an instruction based on its type."""
for action in test: for action in test:
assert len(action) == 1 assert len(action) == 1
@@ -215,7 +216,7 @@ class YamlRunner:
else: else:
raise RuntimeError("Invalid action type %r" % (action_type,)) raise RuntimeError("Invalid action type %r" % (action_type,))
def run_do(self, action) -> None: def run_do(self, action: Any) -> Any:
api = self.client api = self.client
headers = action.pop("headers", None) headers = action.pop("headers", None)
catch = action.pop("catch", None) catch = action.pop("catch", None)
@@ -267,7 +268,7 @@ class YamlRunner:
# Filter out warnings raised by other components. # Filter out warnings raised by other components.
caught_warnings = [ caught_warnings = [
str(w.message) str(w.message) # type: ignore
for w in caught_warnings for w in caught_warnings
if w.category == OpenSearchWarning if w.category == OpenSearchWarning
and str(w.message) not in allowed_warnings and str(w.message) not in allowed_warnings
@@ -275,13 +276,13 @@ class YamlRunner:
# Sorting removes the issue with order raised. We only care about # Sorting removes the issue with order raised. We only care about
# if all warnings are raised in the single API call. # if all warnings are raised in the single API call.
if warn and sorted(warn) != sorted(caught_warnings): if warn and sorted(warn) != sorted(caught_warnings): # type: ignore
raise AssertionError( raise AssertionError(
"Expected warnings not equal to actual warnings: expected=%r actual=%r" "Expected warnings not equal to actual warnings: expected=%r actual=%r"
% (warn, caught_warnings) % (warn, caught_warnings)
) )
def run_catch(self, catch, exception) -> None: def run_catch(self, catch: Any, exception: Any) -> None:
if catch == "param": if catch == "param":
assert isinstance(exception, TypeError) assert isinstance(exception, TypeError)
return return
@@ -296,7 +297,7 @@ class YamlRunner:
) is not None ) is not None
self.last_response = exception.info self.last_response = exception.info
def run_skip(self, skip) -> None: def run_skip(self, skip: Any) -> Any:
global IMPLEMENTED_FEATURES global IMPLEMENTED_FEATURES
if "features" in skip: if "features" in skip:
@@ -318,32 +319,32 @@ class YamlRunner:
if min_version <= (self.opensearch_version()) <= max_version: if min_version <= (self.opensearch_version()) <= max_version:
pytest.skip(reason) pytest.skip(reason)
def run_gt(self, action) -> None: def run_gt(self, action: Any) -> None:
for key, value in action.items(): for key, value in action.items():
value = self._resolve(value) value = self._resolve(value)
assert self._lookup(key) > value assert self._lookup(key) > value
def run_gte(self, action) -> None: def run_gte(self, action: Any) -> None:
for key, value in action.items(): for key, value in action.items():
value = self._resolve(value) value = self._resolve(value)
assert self._lookup(key) >= value assert self._lookup(key) >= value
def run_lt(self, action) -> None: def run_lt(self, action: Any) -> None:
for key, value in action.items(): for key, value in action.items():
value = self._resolve(value) value = self._resolve(value)
assert self._lookup(key) < value assert self._lookup(key) < value
def run_lte(self, action) -> None: def run_lte(self, action: Any) -> None:
for key, value in action.items(): for key, value in action.items():
value = self._resolve(value) value = self._resolve(value)
assert self._lookup(key) <= value assert self._lookup(key) <= value
def run_set(self, action) -> None: def run_set(self, action: Any) -> None:
for key, value in action.items(): for key, value in action.items():
value = self._resolve(value) value = self._resolve(value)
self._state[value] = self._lookup(key) self._state[value] = self._lookup(key)
def run_is_false(self, action) -> None: def run_is_false(self, action: Any) -> None:
try: try:
value = self._lookup(action) value = self._lookup(action)
except AssertionError: except AssertionError:
@@ -351,23 +352,23 @@ class YamlRunner:
else: else:
assert value in FALSEY_VALUES assert value in FALSEY_VALUES
def run_is_true(self, action) -> None: def run_is_true(self, action: Any) -> None:
value = self._lookup(action) value = self._lookup(action)
assert value not in FALSEY_VALUES assert value not in FALSEY_VALUES
def run_length(self, action) -> None: def run_length(self, action: Any) -> None:
for path, expected in action.items(): for path, expected in action.items():
value = self._lookup(path) value = self._lookup(path)
expected = self._resolve(expected) expected = self._resolve(expected)
assert expected == len(value) assert expected == len(value)
def run_match(self, action) -> None: def run_match(self, action: Any) -> None:
for path, expected in action.items(): for path, expected in action.items():
value = self._lookup(path) value = self._lookup(path)
expected = self._resolve(expected) expected = self._resolve(expected)
if ( if (
isinstance(expected, string_types) isinstance(expected, str)
and expected.startswith("/") and expected.startswith("/")
and expected.endswith("/") and expected.endswith("/")
): ):
@@ -379,7 +380,7 @@ class YamlRunner:
else: else:
self._assert_match_equals(value, expected) self._assert_match_equals(value, expected)
def run_contains(self, action) -> None: def run_contains(self, action: Any) -> None:
for path, expected in action.items(): for path, expected in action.items():
value = self._lookup(path) # list[dict[str,str]] is returned value = self._lookup(path) # list[dict[str,str]] is returned
expected = self._resolve(expected) # dict[str, str] expected = self._resolve(expected) # dict[str, str]
@@ -387,7 +388,7 @@ class YamlRunner:
if expected not in value: if expected not in value:
raise AssertionError("%s is not contained by %s" % (expected, value)) raise AssertionError("%s is not contained by %s" % (expected, value))
def run_transform_and_set(self, action) -> None: def run_transform_and_set(self, action: Any) -> None:
for key, value in action.items(): for key, value in action.items():
# Convert #base64EncodeCredentials(id,api_key) to ["id", "api_key"] # Convert #base64EncodeCredentials(id,api_key) to ["id", "api_key"]
if "#base64EncodeCredentials" in value: if "#base64EncodeCredentials" in value:
@@ -397,7 +398,7 @@ class YamlRunner:
(self._lookup(value[0]), self._lookup(value[1])) (self._lookup(value[0]), self._lookup(value[1]))
) )
def _resolve(self, value): def _resolve(self, value: Any) -> Any:
# resolve variables # resolve variables
if isinstance(value, string_types) and "$" in value: if isinstance(value, string_types) and "$" in value:
for k, v in self._state.items(): for k, v in self._state.items():
@@ -422,12 +423,13 @@ class YamlRunner:
value = list(map(self._resolve, value)) value = list(map(self._resolve, value))
return value return value
def _lookup(self, path): def _lookup(self, path: str) -> Any:
# fetch the possibly nested value from last_response # fetch the possibly nested value from last_response
value = self.last_response value: Any = self.last_response
if path == "$body": if path == "$body":
return value return value
path = path.replace(r"\.", "\1") path = path.replace(r"\.", "\1")
step: Any
for step in path.split("."): for step in path.split("."):
if not step: if not step:
continue continue
@@ -449,10 +451,10 @@ class YamlRunner:
value = value[step] value = value[step]
return value return value
def _feature_enabled(self, name) -> bool: def _feature_enabled(self, name: str) -> Any:
return False return False
def _assert_match_equals(self, a, b) -> None: def _assert_match_equals(self, a: Any, b: Any) -> None:
# Handle for large floating points with 'E' # Handle for large floating points with 'E'
if isinstance(b, string_types) and isinstance(a, float) and "e" in repr(a): if isinstance(b, string_types) and isinstance(a, float) and "e" in repr(a):
a = repr(a).replace("e+", "E") a = repr(a).replace("e+", "E")
@@ -460,8 +462,8 @@ class YamlRunner:
assert a == b, "%r does not match %r" % (a, b) assert a == b, "%r does not match %r" % (a, b)
@pytest.fixture(scope="function") @pytest.fixture(scope="function") # type: ignore
def sync_runner(sync_client): def sync_runner(sync_client: Any) -> Any:
return YamlRunner(sync_client) return YamlRunner(sync_client)
@@ -532,8 +534,8 @@ except Exception as e:
if not RUN_ASYNC_REST_API_TESTS: if not RUN_ASYNC_REST_API_TESTS:
@pytest.mark.parametrize("test_spec", YAML_TEST_SPECS) @pytest.mark.parametrize("test_spec", YAML_TEST_SPECS) # type: ignore
def test_rest_api_spec(test_spec, sync_runner) -> None: def test_rest_api_spec(test_spec: Any, sync_runner: Any) -> None:
if test_spec.get("skip", False): if test_spec.get("skip", False):
pytest.skip("Manually skipped in 'SKIP_TESTS'") pytest.skip("Manually skipped in 'SKIP_TESTS'")
sync_runner.use_spec(test_spec) sync_runner.use_spec(test_spec)
@@ -114,7 +114,7 @@ class TestSecurityPlugin(TestCase):
else: else:
assert False assert False
def test_create_user_with_role(self): def test_create_user_with_role(self) -> None:
self.test_create_role() self.test_create_role()
# Test to create user # Test to create user
+45 -38
View File
@@ -30,6 +30,7 @@ from __future__ import unicode_literals
import json import json
import time import time
from typing import Any
from mock import patch from mock import patch
@@ -42,14 +43,14 @@ from .test_cases import TestCase
class DummyConnection(Connection): class DummyConnection(Connection):
def __init__(self, **kwargs) -> None: def __init__(self, **kwargs: Any) -> None:
self.exception = kwargs.pop("exception", None) self.exception = kwargs.pop("exception", None)
self.status, self.data = kwargs.pop("status", 200), kwargs.pop("data", "{}") self.status, self.data = kwargs.pop("status", 200), kwargs.pop("data", "{}")
self.headers = kwargs.pop("headers", {}) self.headers = kwargs.pop("headers", {})
self.calls = [] self.calls: Any = []
super(DummyConnection, self).__init__(**kwargs) super(DummyConnection, self).__init__(**kwargs)
def perform_request(self, *args, **kwargs): def perform_request(self, *args: Any, **kwargs: Any) -> Any:
self.calls.append((args, kwargs)) self.calls.append((args, kwargs))
if self.exception: if self.exception:
raise self.exception raise self.exception
@@ -119,20 +120,20 @@ class TestHostsInfoCallback(TestCase):
chosen = [ chosen = [
i i
for i, node_info in enumerate(nodes) for i, node_info in enumerate(nodes)
if get_host_info(node_info, i) is not None if get_host_info(node_info, i) is not None # type: ignore
] ]
self.assertEqual([1, 2, 3, 4], chosen) self.assertEqual([1, 2, 3, 4], chosen)
class TestTransport(TestCase): class TestTransport(TestCase):
def test_single_connection_uses_dummy_connection_pool(self) -> None: def test_single_connection_uses_dummy_connection_pool(self) -> None:
t = Transport([{}]) t1: Any = Transport([{}])
self.assertIsInstance(t.connection_pool, DummyConnectionPool) self.assertIsInstance(t1.connection_pool, DummyConnectionPool)
t = Transport([{"host": "localhost"}]) t2: Any = Transport([{"host": "localhost"}])
self.assertIsInstance(t.connection_pool, DummyConnectionPool) self.assertIsInstance(t2.connection_pool, DummyConnectionPool)
def test_request_timeout_extracted_from_params_and_passed(self) -> None: def test_request_timeout_extracted_from_params_and_passed(self) -> None:
t = Transport([{}], connection_class=DummyConnection) t: Any = Transport([{}], connection_class=DummyConnection)
t.perform_request("GET", "/", params={"request_timeout": 42}) t.perform_request("GET", "/", params={"request_timeout": 42})
self.assertEqual(1, len(t.get_connection().calls)) self.assertEqual(1, len(t.get_connection().calls))
@@ -143,7 +144,7 @@ class TestTransport(TestCase):
) )
def test_timeout_extracted_from_params_and_passed(self) -> None: def test_timeout_extracted_from_params_and_passed(self) -> None:
t = Transport([{}], connection_class=DummyConnection) t: Any = Transport([{}], connection_class=DummyConnection)
t.perform_request("GET", "/", params={"timeout": 84}) t.perform_request("GET", "/", params={"timeout": 84})
self.assertEqual(1, len(t.get_connection().calls)) self.assertEqual(1, len(t.get_connection().calls))
@@ -154,7 +155,7 @@ class TestTransport(TestCase):
) )
def test_opaque_id(self) -> None: def test_opaque_id(self) -> None:
t = Transport([{}], opaque_id="app-1", connection_class=DummyConnection) t: Any = Transport([{}], opaque_id="app-1", connection_class=DummyConnection)
t.perform_request("GET", "/") t.perform_request("GET", "/")
self.assertEqual(1, len(t.get_connection().calls)) self.assertEqual(1, len(t.get_connection().calls))
@@ -174,7 +175,7 @@ class TestTransport(TestCase):
) )
def test_request_with_custom_user_agent_header(self) -> None: def test_request_with_custom_user_agent_header(self) -> None:
t = Transport([{}], connection_class=DummyConnection) t: Any = Transport([{}], connection_class=DummyConnection)
t.perform_request("GET", "/", headers={"user-agent": "my-custom-value/1.2.3"}) t.perform_request("GET", "/", headers={"user-agent": "my-custom-value/1.2.3"})
self.assertEqual(1, len(t.get_connection().calls)) self.assertEqual(1, len(t.get_connection().calls))
@@ -188,7 +189,9 @@ class TestTransport(TestCase):
) )
def test_send_get_body_as_source(self) -> None: def test_send_get_body_as_source(self) -> None:
t = Transport([{}], send_get_body_as="source", connection_class=DummyConnection) t: Any = Transport(
[{}], send_get_body_as="source", connection_class=DummyConnection
)
t.perform_request("GET", "/", body={}) t.perform_request("GET", "/", body={})
self.assertEqual(1, len(t.get_connection().calls)) self.assertEqual(1, len(t.get_connection().calls))
@@ -197,14 +200,16 @@ class TestTransport(TestCase):
) )
def test_send_get_body_as_post(self) -> None: def test_send_get_body_as_post(self) -> None:
t = Transport([{}], send_get_body_as="POST", connection_class=DummyConnection) t: Any = Transport(
[{}], send_get_body_as="POST", connection_class=DummyConnection
)
t.perform_request("GET", "/", body={}) t.perform_request("GET", "/", body={})
self.assertEqual(1, len(t.get_connection().calls)) self.assertEqual(1, len(t.get_connection().calls))
self.assertEqual(("POST", "/", None, b"{}"), t.get_connection().calls[0][0]) self.assertEqual(("POST", "/", None, b"{}"), t.get_connection().calls[0][0])
def test_body_gets_encoded_into_bytes(self) -> None: def test_body_gets_encoded_into_bytes(self) -> None:
t = Transport([{}], connection_class=DummyConnection) t: Any = Transport([{}], connection_class=DummyConnection)
t.perform_request("GET", "/", body="你好") t.perform_request("GET", "/", body="你好")
self.assertEqual(1, len(t.get_connection().calls)) self.assertEqual(1, len(t.get_connection().calls))
@@ -214,7 +219,7 @@ class TestTransport(TestCase):
) )
def test_body_bytes_get_passed_untouched(self) -> None: def test_body_bytes_get_passed_untouched(self) -> None:
t = Transport([{}], connection_class=DummyConnection) t: Any = Transport([{}], connection_class=DummyConnection)
body = b"\xe4\xbd\xa0\xe5\xa5\xbd" body = b"\xe4\xbd\xa0\xe5\xa5\xbd"
t.perform_request("GET", "/", body=body) t.perform_request("GET", "/", body=body)
@@ -222,7 +227,7 @@ class TestTransport(TestCase):
self.assertEqual(("GET", "/", None, body), t.get_connection().calls[0][0]) self.assertEqual(("GET", "/", None, body), t.get_connection().calls[0][0])
def test_body_surrogates_replaced_encoded_into_bytes(self) -> None: def test_body_surrogates_replaced_encoded_into_bytes(self) -> None:
t = Transport([{}], connection_class=DummyConnection) t: Any = Transport([{}], connection_class=DummyConnection)
t.perform_request("GET", "/", body="你好\uda6a") t.perform_request("GET", "/", body="你好\uda6a")
self.assertEqual(1, len(t.get_connection().calls)) self.assertEqual(1, len(t.get_connection().calls))
@@ -232,26 +237,26 @@ class TestTransport(TestCase):
) )
def test_kwargs_passed_on_to_connections(self) -> None: def test_kwargs_passed_on_to_connections(self) -> None:
t = Transport([{"host": "google.com"}], port=123) t: Any = Transport([{"host": "google.com"}], port=123)
self.assertEqual(1, len(t.connection_pool.connections)) self.assertEqual(1, len(t.connection_pool.connections))
self.assertEqual("http://google.com:123", t.connection_pool.connections[0].host) self.assertEqual("http://google.com:123", t.connection_pool.connections[0].host)
def test_kwargs_passed_on_to_connection_pool(self) -> None: def test_kwargs_passed_on_to_connection_pool(self) -> None:
dt = object() dt = object()
t = Transport([{}, {}], dead_timeout=dt) t: Any = Transport([{}, {}], dead_timeout=dt)
self.assertIs(dt, t.connection_pool.dead_timeout) self.assertIs(dt, t.connection_pool.dead_timeout)
def test_custom_connection_class(self) -> None: def test_custom_connection_class(self) -> None:
class MyConnection(object): class MyConnection(Connection):
def __init__(self, **kwargs): def __init__(self, **kwargs: Any) -> None:
self.kwargs = kwargs self.kwargs = kwargs
t = Transport([{}], connection_class=MyConnection) t: Any = Transport([{}], connection_class=MyConnection)
self.assertEqual(1, len(t.connection_pool.connections)) self.assertEqual(1, len(t.connection_pool.connections))
self.assertIsInstance(t.connection_pool.connections[0], MyConnection) self.assertIsInstance(t.connection_pool.connections[0], MyConnection)
def test_add_connection(self) -> None: def test_add_connection(self) -> None:
t = Transport([{}], randomize_hosts=False) t: Any = Transport([{}], randomize_hosts=False)
t.add_connection({"host": "google.com", "port": 1234}) t.add_connection({"host": "google.com", "port": 1234})
self.assertEqual(2, len(t.connection_pool.connections)) self.assertEqual(2, len(t.connection_pool.connections))
@@ -260,7 +265,7 @@ class TestTransport(TestCase):
) )
def test_request_will_fail_after_X_retries(self) -> None: def test_request_will_fail_after_X_retries(self) -> None:
t = Transport( t: Any = Transport(
[{"exception": ConnectionError("abandon ship")}], [{"exception": ConnectionError("abandon ship")}],
connection_class=DummyConnection, connection_class=DummyConnection,
) )
@@ -269,7 +274,7 @@ class TestTransport(TestCase):
self.assertEqual(4, len(t.get_connection().calls)) self.assertEqual(4, len(t.get_connection().calls))
def test_failed_connection_will_be_marked_as_dead(self) -> None: def test_failed_connection_will_be_marked_as_dead(self) -> None:
t = Transport( t: Any = Transport(
[{"exception": ConnectionError("abandon ship")}] * 2, [{"exception": ConnectionError("abandon ship")}] * 2,
connection_class=DummyConnection, connection_class=DummyConnection,
) )
@@ -279,7 +284,7 @@ class TestTransport(TestCase):
def test_resurrected_connection_will_be_marked_as_live_on_success(self) -> None: def test_resurrected_connection_will_be_marked_as_live_on_success(self) -> None:
for method in ("GET", "HEAD"): for method in ("GET", "HEAD"):
t = Transport([{}, {}], connection_class=DummyConnection) t: Any = Transport([{}, {}], connection_class=DummyConnection)
con1 = t.connection_pool.get_connection() con1 = t.connection_pool.get_connection()
con2 = t.connection_pool.get_connection() con2 = t.connection_pool.get_connection()
t.connection_pool.mark_dead(con1) t.connection_pool.mark_dead(con1)
@@ -290,7 +295,7 @@ class TestTransport(TestCase):
self.assertEqual(1, len(t.connection_pool.dead_count)) self.assertEqual(1, len(t.connection_pool.dead_count))
def test_sniff_will_use_seed_connections(self) -> None: def test_sniff_will_use_seed_connections(self) -> None:
t = Transport([{"data": CLUSTER_NODES}], connection_class=DummyConnection) t: Any = Transport([{"data": CLUSTER_NODES}], connection_class=DummyConnection)
t.set_connections([{"data": "invalid"}]) t.set_connections([{"data": "invalid"}])
t.sniff_hosts() t.sniff_hosts()
@@ -298,7 +303,7 @@ class TestTransport(TestCase):
self.assertEqual("http://1.1.1.1:123", t.get_connection().host) self.assertEqual("http://1.1.1.1:123", t.get_connection().host)
def test_sniff_on_start_fetches_and_uses_nodes_list(self) -> None: def test_sniff_on_start_fetches_and_uses_nodes_list(self) -> None:
t = Transport( t: Any = Transport(
[{"data": CLUSTER_NODES}], [{"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_on_start=True, sniff_on_start=True,
@@ -307,7 +312,7 @@ class TestTransport(TestCase):
self.assertEqual("http://1.1.1.1:123", t.get_connection().host) self.assertEqual("http://1.1.1.1:123", t.get_connection().host)
def test_sniff_on_start_ignores_sniff_timeout(self) -> None: def test_sniff_on_start_ignores_sniff_timeout(self) -> None:
t = Transport( t: Any = Transport(
[{"data": CLUSTER_NODES}], [{"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_on_start=True, sniff_on_start=True,
@@ -319,7 +324,7 @@ class TestTransport(TestCase):
) )
def test_sniff_uses_sniff_timeout(self) -> None: def test_sniff_uses_sniff_timeout(self) -> None:
t = Transport( t: Any = Transport(
[{"data": CLUSTER_NODES}], [{"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_timeout=42, sniff_timeout=42,
@@ -330,8 +335,8 @@ class TestTransport(TestCase):
t.seed_connections[0].calls[0], t.seed_connections[0].calls[0],
) )
def test_sniff_reuses_connection_instances_if_possible(self): def test_sniff_reuses_connection_instances_if_possible(self) -> None:
t = Transport( t: Any = Transport(
[{"data": CLUSTER_NODES}, {"host": "1.1.1.1", "port": 123}], [{"data": CLUSTER_NODES}, {"host": "1.1.1.1", "port": 123}],
connection_class=DummyConnection, connection_class=DummyConnection,
randomize_hosts=False, randomize_hosts=False,
@@ -342,8 +347,8 @@ class TestTransport(TestCase):
self.assertEqual(1, len(t.connection_pool.connections)) self.assertEqual(1, len(t.connection_pool.connections))
self.assertIs(connection, t.get_connection()) self.assertIs(connection, t.get_connection())
def test_sniff_on_fail_triggers_sniffing_on_fail(self): def test_sniff_on_fail_triggers_sniffing_on_fail(self) -> None:
t = Transport( t: Any = Transport(
[{"exception": ConnectionError("abandon ship")}, {"data": CLUSTER_NODES}], [{"exception": ConnectionError("abandon ship")}, {"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_on_connection_fail=True, sniff_on_connection_fail=True,
@@ -356,9 +361,11 @@ class TestTransport(TestCase):
self.assertEqual("http://1.1.1.1:123", t.get_connection().host) self.assertEqual("http://1.1.1.1:123", t.get_connection().host)
@patch("opensearchpy.transport.Transport.sniff_hosts") @patch("opensearchpy.transport.Transport.sniff_hosts")
def test_sniff_on_fail_failing_does_not_prevent_retires(self, sniff_hosts): def test_sniff_on_fail_failing_does_not_prevent_retires(
self, sniff_hosts: Any
) -> None:
sniff_hosts.side_effect = [TransportError("sniff failed")] sniff_hosts.side_effect = [TransportError("sniff failed")]
t = Transport( t: Any = Transport(
[{"exception": ConnectionError("abandon ship")}, {"data": CLUSTER_NODES}], [{"exception": ConnectionError("abandon ship")}, {"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_on_connection_fail=True, sniff_on_connection_fail=True,
@@ -374,7 +381,7 @@ class TestTransport(TestCase):
self.assertEqual(1, len(conn_data.calls)) self.assertEqual(1, len(conn_data.calls))
def test_sniff_after_n_seconds(self) -> None: def test_sniff_after_n_seconds(self) -> None:
t = Transport( t: Any = Transport(
[{"data": CLUSTER_NODES}], [{"data": CLUSTER_NODES}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniffer_timeout=5, sniffer_timeout=5,
@@ -394,7 +401,7 @@ class TestTransport(TestCase):
def test_sniff_7x_publish_host(self) -> None: def test_sniff_7x_publish_host(self) -> None:
# Test the response shaped when a 7.x node has publish_host set # Test the response shaped when a 7.x node has publish_host set
# and the returend data is shaped in the fqdn/ip:port format. # and the returend data is shaped in the fqdn/ip:port format.
t = Transport( t: Any = Transport(
[{"data": CLUSTER_NODES_7x_PUBLISH_HOST}], [{"data": CLUSTER_NODES_7x_PUBLISH_HOST}],
connection_class=DummyConnection, connection_class=DummyConnection,
sniff_timeout=42, sniff_timeout=42,
+15 -14
View File
@@ -27,11 +27,12 @@
import time import time
from typing import Any
from opensearchpy import OpenSearch from opensearchpy import OpenSearch
def wipe_cluster(client) -> None: def wipe_cluster(client: Any) -> None:
"""Wipes a cluster clean between test cases""" """Wipes a cluster clean between test cases"""
close_after_wipe = False close_after_wipe = False
try: try:
@@ -59,9 +60,9 @@ def wipe_cluster(client) -> None:
client.close() client.close()
def wipe_cluster_settings(client) -> None: def wipe_cluster_settings(client: Any) -> None:
settings = client.cluster.get_settings() settings = client.cluster.get_settings()
new_settings = {} new_settings: Any = {}
for name, value in settings.items(): for name, value in settings.items():
if value: if value:
new_settings.setdefault(name, {}) new_settings.setdefault(name, {})
@@ -71,7 +72,7 @@ def wipe_cluster_settings(client) -> None:
client.cluster.put_settings(body=new_settings) client.cluster.put_settings(body=new_settings)
def wipe_snapshots(client): def wipe_snapshots(client: Any) -> None:
"""Deletes all the snapshots and repositories from the cluster""" """Deletes all the snapshots and repositories from the cluster"""
in_progress_snapshots = [] in_progress_snapshots = []
@@ -96,14 +97,14 @@ def wipe_snapshots(client):
assert in_progress_snapshots == [] assert in_progress_snapshots == []
def wipe_data_streams(client) -> None: def wipe_data_streams(client: Any) -> None:
try: try:
client.indices.delete_data_stream(name="*", expand_wildcards="all") client.indices.delete_data_stream(name="*", expand_wildcards="all")
except Exception: except Exception:
client.indices.delete_data_stream(name="*") client.indices.delete_data_stream(name="*")
def wipe_indices(client) -> None: def wipe_indices(client: Any) -> None:
client.indices.delete( client.indices.delete(
index="*,-.ds-ilm-history-*", index="*,-.ds-ilm-history-*",
expand_wildcards="all", expand_wildcards="all",
@@ -111,7 +112,7 @@ def wipe_indices(client) -> None:
) )
def wipe_searchable_snapshot_indices(client) -> None: def wipe_searchable_snapshot_indices(client: Any) -> None:
cluster_metadata = client.cluster.state( cluster_metadata = client.cluster.state(
metric="metadata", metric="metadata",
filter_path="metadata.indices.*.settings.index.store.snapshot", filter_path="metadata.indices.*.settings.index.store.snapshot",
@@ -121,17 +122,17 @@ def wipe_searchable_snapshot_indices(client) -> None:
client.indices.delete(index=index) client.indices.delete(index=index)
def wipe_slm_policies(client) -> None: def wipe_slm_policies(client: Any) -> None:
for policy in client.slm.get_lifecycle(): for policy in client.slm.get_lifecycle():
client.slm.delete_lifecycle(policy_id=policy["name"]) client.slm.delete_lifecycle(policy_id=policy["name"])
def wipe_auto_follow_patterns(client) -> None: def wipe_auto_follow_patterns(client: Any) -> None:
for pattern in client.ccr.get_auto_follow_pattern()["patterns"]: for pattern in client.ccr.get_auto_follow_pattern()["patterns"]:
client.ccr.delete_auto_follow_pattern(name=pattern["name"]) client.ccr.delete_auto_follow_pattern(name=pattern["name"])
def wipe_node_shutdown_metadata(client) -> None: def wipe_node_shutdown_metadata(client: Any) -> None:
shutdown_status = client.shutdown.get_node() shutdown_status = client.shutdown.get_node()
# If response contains these two keys the feature flag isn't enabled # If response contains these two keys the feature flag isn't enabled
# on this cluster so skip this step now. # on this cluster so skip this step now.
@@ -143,14 +144,14 @@ def wipe_node_shutdown_metadata(client) -> None:
client.shutdown.delete_node(node_id=node_id) client.shutdown.delete_node(node_id=node_id)
def wipe_tasks(client) -> None: def wipe_tasks(client: Any) -> None:
tasks = client.tasks.list() tasks = client.tasks.list()
for node_name, node in tasks.get("node", {}).items(): for node_name, node in tasks.get("node", {}).items():
for task_id in node.get("tasks", ()): for task_id in node.get("tasks", ()):
client.tasks.cancel(task_id=task_id, wait_for_completion=True) client.tasks.cancel(task_id=task_id, wait_for_completion=True)
def wait_for_pending_tasks(client, filter, timeout: int = 30) -> None: def wait_for_pending_tasks(client: Any, filter: Any, timeout: int = 30) -> None:
end_time = time.time() + timeout end_time = time.time() + timeout
while time.time() < end_time: while time.time() < end_time:
tasks = client.cat.tasks(detailed=True).split("\n") tasks = client.cat.tasks(detailed=True).split("\n")
@@ -158,7 +159,7 @@ def wait_for_pending_tasks(client, filter, timeout: int = 30) -> None:
break break
def wait_for_pending_datafeeds_and_jobs(client, timeout: int = 30) -> None: def wait_for_pending_datafeeds_and_jobs(client: Any, timeout: int = 30) -> None:
end_time = time.time() + timeout end_time = time.time() + timeout
while time.time() < end_time: while time.time() < end_time:
if ( if (
@@ -171,7 +172,7 @@ def wait_for_pending_datafeeds_and_jobs(client, timeout: int = 30) -> None:
break break
def wait_for_cluster_state_updates_to_finish(client, timeout: int = 30) -> None: def wait_for_cluster_state_updates_to_finish(client: Any, timeout: int = 30) -> None:
end_time = time.time() + timeout end_time = time.time() + timeout
while time.time() < end_time: while time.time() < end_time:
if not client.cluster.pending_tasks().get("tasks", ()): if not client.cluster.pending_tasks().get("tasks", ()):
+8 -7
View File
@@ -38,13 +38,14 @@ import shlex
import shutil import shutil
import sys import sys
import tempfile import tempfile
from typing import Any
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
tmp_dir = None tmp_dir = None
@contextlib.contextmanager @contextlib.contextmanager # type: ignore
def set_tmp_dir(): def set_tmp_dir() -> None:
global tmp_dir global tmp_dir
tmp_dir = tempfile.mkdtemp() tmp_dir = tempfile.mkdtemp()
yield tmp_dir yield tmp_dir
@@ -52,7 +53,7 @@ def set_tmp_dir():
tmp_dir = None tmp_dir = None
def run(*argv, expect_exit_code: int = 0) -> None: def run(*argv: Any, expect_exit_code: int = 0) -> None:
global tmp_dir global tmp_dir
if tmp_dir is None: if tmp_dir is None:
os.chdir(base_dir) os.chdir(base_dir)
@@ -70,9 +71,9 @@ def run(*argv, expect_exit_code: int = 0) -> None:
exit(exit_code or 1) exit(exit_code or 1)
def test_dist(dist) -> None: def test_dist(dist: Any) -> None:
with set_tmp_dir() as tmp_dir: with set_tmp_dir() as tmp_dir: # type: ignore
dist_name = re.match( dist_name = re.match( # type: ignore
r"^(opensearchpy\d*)-", r"^(opensearchpy\d*)-",
os.path.basename(dist) os.path.basename(dist)
.replace("opensearch-py", "opensearchpy") .replace("opensearch-py", "opensearchpy")
@@ -216,7 +217,7 @@ def main() -> None:
# alpha/beta/rc -> aN/bN/rcN # alpha/beta/rc -> aN/bN/rcN
else: else:
pre_number = re.search(r"-(a|b|rc)(?:lpha|eta|)(\d+)$", expect_version) pre_number = re.search(r"-(a|b|rc)(?:lpha|eta|)(\d+)$", expect_version)
version = version + pre_number.group(1) + pre_number.group(2) version = version + pre_number.group(1) + pre_number.group(2) # type: ignore
expect_version = re.sub( expect_version = re.sub(
r"(?:-(?:SNAPSHOT|alpha\d+|beta\d+|rc\d+))+$", "", expect_version r"(?:-(?:SNAPSHOT|alpha\d+|beta\d+|rc\d+))+$", "", expect_version

Some files were not shown because too many files have changed in this diff Show More