From 6e94bf76adbbbb2fe5b927a3933ed535cd738387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Honza=20Kr=C3=A1l?= Date: Tue, 22 Mar 2016 21:04:07 +0100 Subject: [PATCH] 5.0 compatibility --- Changelog.rst | 5 + README | 8 +- docs/conf.py | 6 +- elasticsearch/__init__.py | 2 +- elasticsearch/client/__init__.py | 50 ++++--- elasticsearch/client/cat.py | 4 +- elasticsearch/client/cluster.py | 5 +- elasticsearch/client/indices.py | 135 ++---------------- elasticsearch/client/ingest.py | 63 ++++++++ elasticsearch/client/tasks.py | 45 ++++++ elasticsearch/helpers/__init__.py | 5 +- setup.py | 2 +- test_elasticsearch/test_server/test_common.py | 8 ++ .../test_server/test_helpers.py | 4 +- 14 files changed, 187 insertions(+), 155 deletions(-) create mode 100644 elasticsearch/client/ingest.py create mode 100644 elasticsearch/client/tasks.py diff --git a/Changelog.rst b/Changelog.rst index ce27413e..4363663e 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -3,6 +3,11 @@ Changelog ========= +5.0.0 (dev) +----------- + +Version compatible with elasticsearch 5.0 + 2.3.0 (2016-02-29) ------------------ diff --git a/README b/README index 5473fcd8..8e4697ab 100644 --- a/README +++ b/README @@ -28,6 +28,9 @@ Compatibility The library is compatible with all Elasticsearch versions since ``0.90.x`` but you **have to use a matching major version**: +For **Elasticsearch 5.0** and later, use the major version 5 (``5.x.y``) of the +library. + For **Elasticsearch 2.0** and later, use the major version 2 (``2.x.y``) of the library. @@ -40,6 +43,9 @@ library. The recommended way to set your requirements in your `setup.py` or `requirements.txt` is:: + # Elasticsearch 5.x + elasticsearch>=5.0.0,<6.0.0 + # Elasticsearch 2.x elasticsearch>=2.0.0,<3.0.0 @@ -49,7 +55,7 @@ The recommended way to set your requirements in your `setup.py` or # Elasticsearch 0.90.x elasticsearch<1.0.0 -The development is happening on ``master`` and ``1.x`` branches, respectively. +The development is happening on ``master`` and ``2.x`` branches respectively. Installation ------------ diff --git a/docs/conf.py b/docs/conf.py index 38b0b26d..0a77fefd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,11 +50,11 @@ copyright = u'2013, Honza Král' # built documents. # -import elasticsearch + # The short X.Y version. -version = elasticsearch.__versionstr__ +version = '5.0.0' # The full version, including alpha/beta/rc tags. -release = version +release = '5.0.0-dev' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/elasticsearch/__init__.py b/elasticsearch/__init__.py index 405bc212..2a5df93b 100644 --- a/elasticsearch/__init__.py +++ b/elasticsearch/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import -VERSION = (2, 3, 0) +VERSION = (5, 0, 0, 'dev') __version__ = VERSION __versionstr__ = '.'.join(map(str, VERSION)) diff --git a/elasticsearch/client/__init__.py b/elasticsearch/client/__init__.py index 7b8ff559..5ad83261 100644 --- a/elasticsearch/client/__init__.py +++ b/elasticsearch/client/__init__.py @@ -6,10 +6,12 @@ from ..transport import Transport from ..exceptions import TransportError from ..compat import string_types, urlparse from .indices import IndicesClient +from .ingest import IngestClient from .cluster import ClusterClient from .cat import CatClient from .nodes import NodesClient from .snapshot import SnapshotClient +from .tasks import TasksClient from .utils import query_params, _make_path, SKIP_IN_PATH logger = logging.getLogger('elasticsearch') @@ -64,13 +66,15 @@ class Elasticsearch(object): Elasticsearch low-level client. Provides a straightforward mapping from Python to ES REST endpoints. - The instance has attributes ``cat``, ``cluster``, ``indices``, ``nodes`` - and ``snapshot`` that provide access to instances of + The instance has attributes ``cat``, ``cluster``, ``indices``, ``ingest``, + ``nodes``, ``snapshot`` and ``tasks`` that provide access to instances of :class:`~elasticsearch.client.CatClient`, :class:`~elasticsearch.client.ClusterClient`, :class:`~elasticsearch.client.IndicesClient`, - :class:`~elasticsearch.client.NodesClient` and - :class:`~elasticsearch.client.SnapshotClient` respectively. This is the + :class:`~elasticsearch.client.IngestClient`, + :class:`~elasticsearch.client.NodesClient`, + :class:`~elasticsearch.client.SnapshotClient` and + :class:`~elasticsearch.client.TasksClient` respectively. This is the preferred (and only supported) way to get access to those classes and their methods. @@ -170,10 +174,12 @@ class Elasticsearch(object): # namespaced clients for compatibility with API names # use weakref to make GC's work a little easier self.indices = IndicesClient(weakref.proxy(self)) + self.ingest = IngestClient(weakref.proxy(self)) self.cluster = ClusterClient(weakref.proxy(self)) self.cat = CatClient(weakref.proxy(self)) self.nodes = NodesClient(weakref.proxy(self)) self.snapshot = SnapshotClient(weakref.proxy(self)) + self.tasks = TasksClient(weakref.proxy(self)) def __repr__(self): try: @@ -214,7 +220,7 @@ class Elasticsearch(object): """ return self.transport.perform_request('GET', '/', params=params) - @query_params('consistency', 'parent', 'refresh', 'routing', + @query_params('consistency', 'parent', 'pipeline', 'refresh', 'routing', 'timeout', 'timestamp', 'ttl', 'version', 'version_type') def create(self, index, doc_type, body, id=None, params=None): """ @@ -242,8 +248,8 @@ class Elasticsearch(object): """ return self.index(index, doc_type, body, id=id, params=params, op_type='create') - @query_params('consistency', 'op_type', 'parent', 'refresh', 'routing', - 'timeout', 'timestamp', 'ttl', 'version', 'version_type') + @query_params('consistency', 'op_type', 'parent', 'pipeline', 'refresh', + 'routing', 'timeout', 'timestamp', 'ttl', 'version', 'version_type') def index(self, index, doc_type, body, id=None, params=None): """ Adds or updates a typed JSON document in a specific index, making it searchable. @@ -258,6 +264,7 @@ class Elasticsearch(object): :arg op_type: Explicit operation type, default 'index', valid choices are: 'index', 'create' :arg parent: ID of the parent document + :arg pipeline: The pipeline id to preprocess incoming documents with :arg refresh: Refresh the index after performing the operation :arg routing: Specific routing value :arg timeout: Explicit operation timeout @@ -295,8 +302,8 @@ class Elasticsearch(object): for param in (index, doc_type, id): if param in SKIP_IN_PATH: raise ValueError("Empty value passed for a required argument.") - return self.transport.perform_request('HEAD', _make_path(index, doc_type, - id), params=params) + return self.transport.perform_request('HEAD', _make_path(index, + doc_type, id), params=params) @query_params('_source', '_source_exclude', '_source_include', 'fields', 'parent', 'preference', 'realtime', 'refresh', 'routing', 'version', @@ -402,8 +409,8 @@ class Elasticsearch(object): return self.transport.perform_request('GET', _make_path(index, doc_type, '_mget'), params=params, body=body) - @query_params('consistency', 'detect_noop', 'fields', 'lang', 'parent', - 'refresh', 'retry_on_conflict', 'routing', 'script', 'script_id', + @query_params('consistency', 'fields', 'lang', 'parent', 'refresh', + 'retry_on_conflict', 'routing', 'script', 'script_id', 'scripted_upsert', 'timeout', 'timestamp', 'ttl', 'version', 'version_type') def update(self, index, doc_type, id, body=None, params=None): @@ -417,9 +424,6 @@ class Elasticsearch(object): :arg body: The request definition using either `script` or partial `doc` :arg consistency: Explicit write consistency setting for the operation, valid choices are: 'one', 'quorum', 'all' - :arg detect_noop: Specifying as true will cause Elasticsearch to check - if there are changes and, if there aren't, turn the update request - into a noop. :arg fields: A comma-separated list of fields to return in the response :arg lang: The script language (default: groovy) :arg parent: ID of the parent document. Is is only used for routing and @@ -504,7 +508,7 @@ class Elasticsearch(object): :arg scroll: Specify how long a consistent view of the index should be maintained for scrolled search :arg search_type: Search operation type, valid choices are: - 'query_then_fetch', 'dfs_query_then_fetch', 'count', 'scan' + 'query_then_fetch', 'dfs_query_then_fetch' :arg size: Number of hits to return (default: 10) :arg sort: A comma-separated list of : pairs :arg stats: Specific 'tag' of the request for logging and statistical @@ -591,7 +595,7 @@ class Elasticsearch(object): maintained for scrolled search :arg search_type: Search operation type, valid choices are: 'query_then_fetch', 'query_and_fetch', 'dfs_query_then_fetch', - 'dfs_query_and_fetch', 'count', 'scan' + 'dfs_query_and_fetch' """ return self.transport.perform_request('GET', _make_path(index, doc_type, '_search', 'template'), params=params, body=body) @@ -746,7 +750,8 @@ class Elasticsearch(object): return self.transport.perform_request('GET', _make_path(index, doc_type, '_count'), params=params, body=body) - @query_params('consistency', 'fields', 'refresh', 'routing', 'timeout') + @query_params('consistency', 'fields', 'pipeline', 'refresh', 'routing', + 'timeout') def bulk(self, body, index=None, doc_type=None, params=None): """ Perform many index/delete operations in a single API call. @@ -763,6 +768,7 @@ class Elasticsearch(object): valid choices are: 'one', 'quorum', 'all' :arg fields: Default comma-separated list of fields to return in the response for updates + :arg pipeline: The pipeline id to preprocess incoming documents with :arg refresh: Refresh the index after performing the operation :arg routing: Specific routing value :arg timeout: Explicit operation timeout @@ -785,7 +791,7 @@ class Elasticsearch(object): default :arg search_type: Search operation type, valid choices are: 'query_then_fetch', 'query_and_fetch', 'dfs_query_then_fetch', - 'dfs_query_and_fetch', 'count', 'scan' + 'dfs_query_and_fetch' """ if body in SKIP_IN_PATH: raise ValueError("Empty value passed for a required argument 'body'.") @@ -941,9 +947,9 @@ class Elasticsearch(object): return self.transport.perform_request('GET', _make_path(index, doc_type, id, '_percolate', 'count'), params=params, body=body) - @query_params('dfs', 'field_statistics', 'fields', 'offsets', 'parent', - 'payloads', 'positions', 'preference', 'realtime', 'routing', - 'term_statistics', 'version', 'version_type') + @query_params('field_statistics', 'fields', 'offsets', 'parent', 'payloads', + 'positions', 'preference', 'realtime', 'routing', 'term_statistics', + 'version', 'version_type') def termvectors(self, index, doc_type, id=None, body=None, params=None): """ Returns information and statistics on terms in the fields of a @@ -959,8 +965,6 @@ class Elasticsearch(object): be supplied. :arg body: Define parameters and or supply a document to get termvectors for. See documentation. - :arg dfs: Specifies if distributed frequencies should be returned - instead shard frequencies., default False :arg field_statistics: Specifies if document count, sum of document frequencies and sum of total term frequencies should be returned., default True diff --git a/elasticsearch/client/cat.py b/elasticsearch/client/cat.py index d900c1b4..29869d2a 100644 --- a/elasticsearch/client/cat.py +++ b/elasticsearch/client/cat.py @@ -311,7 +311,7 @@ class CatClient(NamespacedClient): return self.transport.perform_request('GET', '/_cat/repositories', params=params) - @query_params('h', 'help', 'master_timeout', 'v') + @query_params('h', 'help', 'ignore_unavailable', 'master_timeout', 'v') def snapshots(self, repository=None, params=None): """ ``_ @@ -320,6 +320,8 @@ class CatClient(NamespacedClient): information :arg h: Comma-separated list of column names to display :arg help: Return help information, default False + :arg ignore_unavailable: Set to true to ignore unavailable snapshots, + default False :arg master_timeout: Explicit operation timeout for connection to master node :arg v: Verbose mode. Display column headers, default False diff --git a/elasticsearch/client/cluster.py b/elasticsearch/client/cluster.py index ee626262..d3b78b51 100644 --- a/elasticsearch/client/cluster.py +++ b/elasticsearch/client/cluster.py @@ -115,13 +115,16 @@ class ClusterClient(NamespacedClient): return self.transport.perform_request('POST', '/_cluster/reroute', params=params, body=body) - @query_params('flat_settings', 'master_timeout', 'timeout') + @query_params('flat_settings', 'include_defaults', 'master_timeout', + 'timeout') def get_settings(self, params=None): """ Get cluster settings. ``_ :arg flat_settings: Return settings in flat format (default: false) + :arg include_defaults: Whether to return all default clusters setting., + default False :arg master_timeout: Explicit operation timeout for connection to master node :arg timeout: Explicit operation timeout diff --git a/elasticsearch/client/indices.py b/elasticsearch/client/indices.py index 7545166a..8a71f996 100644 --- a/elasticsearch/client/indices.py +++ b/elasticsearch/client/indices.py @@ -1,8 +1,8 @@ from .utils import NamespacedClient, query_params, _make_path, SKIP_IN_PATH class IndicesClient(NamespacedClient): - @query_params('analyzer', 'char_filters', 'field', 'filters', 'format', - 'prefer_local', 'text', 'tokenizer') + @query_params('analyzer', 'attributes', 'char_filters', 'explain', 'field', + 'filters', 'format', 'prefer_local', 'text', 'tokenizer') def analyze(self, index=None, body=None, params=None): """ Perform the analysis process on a text and return the tokens breakdown of the text. @@ -11,8 +11,12 @@ class IndicesClient(NamespacedClient): :arg index: The name of the index to scope the operation :arg body: The text on which the analysis should be performed :arg analyzer: The name of the analyzer to use + :arg attributes: A comma-separated list of token attributes to output, + this parameter works only with `explain=true` :arg char_filters: A comma-separated list of character filters to use for the analysis + :arg explain: With `true`, outputs more advanced details. (default: + false) :arg field: Use the analyzer configured for this field (instead of passing the analyzer name) :arg filters: A comma-separated list of filters to use for the analysis @@ -513,7 +517,7 @@ class IndicesClient(NamespacedClient): _make_path('_template', name), params=params) @query_params('allow_no_indices', 'expand_wildcards', 'flat_settings', - 'human', 'ignore_unavailable', 'local') + 'human', 'ignore_unavailable', 'include_defaults', 'local') def get_settings(self, index=None, name=None, params=None): """ Retrieve settings for one or more (or all) indices. @@ -533,6 +537,8 @@ class IndicesClient(NamespacedClient): readable format., default False :arg ignore_unavailable: Whether specified concrete indices should be ignored when unavailable (missing or closed) + :arg include_defaults: Whether to return all default setting for each of + the indices., default False :arg local: Return local information, do not retrieve the state from master node (default: false) """ @@ -540,7 +546,7 @@ class IndicesClient(NamespacedClient): '_settings', name), params=params) @query_params('allow_no_indices', 'expand_wildcards', 'flat_settings', - 'ignore_unavailable', 'master_timeout') + 'ignore_unavailable', 'master_timeout', 'preserve_existing') def put_settings(self, body, index=None, params=None): """ Change specific index level settings in real time. @@ -559,96 +565,15 @@ class IndicesClient(NamespacedClient): :arg ignore_unavailable: Whether specified concrete indices should be ignored when unavailable (missing or closed) :arg master_timeout: Specify timeout for connection to master + :arg preserve_existing: Whether to update existing settings. If set to + `true` existing settings on an index remain unchanged, the default + is `false` """ if body in SKIP_IN_PATH: raise ValueError("Empty value passed for a required argument 'body'.") return self.transport.perform_request('PUT', _make_path(index, '_settings'), params=params, body=body) - @query_params('allow_no_indices', 'expand_wildcards', 'ignore_unavailable', - 'master_timeout', 'request_cache') - def put_warmer(self, name, body, index=None, doc_type=None, params=None): - """ - Create an index warmer to run registered search requests to warm up the - index before it is available for search. - ``_ - - :arg name: The name of the warmer - :arg body: The search request definition for the warmer (query, filters, - facets, sorting, etc) - :arg index: A comma-separated list of index names to register the warmer - for; use `_all` or omit to perform the operation on all indices - :arg doc_type: A comma-separated list of document types to register the - warmer for; leave empty to perform the operation on all types - :arg allow_no_indices: Whether to ignore if a wildcard indices - expression resolves into no concrete indices in the search request - to warm. (This includes `_all` string or when no indices have been - specified) - :arg expand_wildcards: Whether to expand wildcard expression to concrete - indices that are open, closed or both, in the search request to - warm., default 'open', valid choices are: 'open', 'closed', 'none', - 'all' - :arg ignore_unavailable: Whether specified concrete indices should be - ignored when unavailable (missing or closed) in the search request - to warm - :arg master_timeout: Specify timeout for connection to master - :arg request_cache: Specify whether the request to be warmed should use - the request cache, defaults to index level setting - """ - for param in (name, body): - if param in SKIP_IN_PATH: - raise ValueError("Empty value passed for a required argument.") - return self.transport.perform_request('PUT', _make_path(index, - doc_type, '_warmer', name), params=params, body=body) - - @query_params('allow_no_indices', 'expand_wildcards', 'ignore_unavailable', - 'local') - def get_warmer(self, index=None, doc_type=None, name=None, params=None): - """ - Retreieve an index warmer. - ``_ - - :arg index: A comma-separated list of index names to restrict the - operation; use `_all` to perform the operation on all indices - :arg doc_type: A comma-separated list of document types to restrict the - operation; leave empty to perform the operation on all types - :arg name: The name of the warmer (supports wildcards); leave empty to - get all warmers - :arg allow_no_indices: Whether to ignore if a wildcard indices - expression resolves into no concrete indices. (This includes `_all` - string or when no indices have been specified) - :arg expand_wildcards: Whether to expand wildcard expression to concrete - indices that are open, closed or both., default 'open', valid - choices are: 'open', 'closed', 'none', 'all' - :arg ignore_unavailable: Whether specified concrete indices should be - ignored when unavailable (missing or closed) - :arg local: Return local information, do not retrieve the state from - master node (default: false) - """ - return self.transport.perform_request('GET', _make_path(index, - doc_type, '_warmer', name), params=params) - - @query_params('master_timeout') - def delete_warmer(self, index, name, params=None): - """ - Delete an index warmer. - ``_ - - :arg index: A comma-separated list of index names to delete warmers from - (supports wildcards); use `_all` to perform the operation on all - indices. - :arg name: A comma-separated list of warmer names to delete (supports - wildcards); use `_all` to delete all warmers in the specified - indices. You must specify a name either in the uri or in the - parameters. - :arg master_timeout: Specify timeout for connection to master - """ - for param in (index, name): - if param in SKIP_IN_PATH: - raise ValueError("Empty value passed for a required argument.") - return self.transport.perform_request('DELETE', _make_path(index, - '_warmer', name), params=params) - @query_params('completion_fields', 'fielddata_fields', 'fields', 'groups', 'human', 'level', 'types') def stats(self, index=None, metric=None, params=None): @@ -678,7 +603,7 @@ class IndicesClient(NamespacedClient): '_stats', metric), params=params) @query_params('allow_no_indices', 'expand_wildcards', 'human', - 'ignore_unavailable', 'operation_threading') + 'ignore_unavailable', 'operation_threading', 'verbose') def segments(self, index=None, params=None): """ Provide low level segments information that a Lucene index (shard level) is built with. @@ -697,41 +622,11 @@ class IndicesClient(NamespacedClient): :arg ignore_unavailable: Whether specified concrete indices should be ignored when unavailable (missing or closed) :arg operation_threading: TODO: ? + :arg verbose: Includes detailed memory usage by Lucene., default False """ return self.transport.perform_request('GET', _make_path(index, '_segments'), params=params) - @query_params('allow_no_indices', 'expand_wildcards', 'flush', - 'ignore_unavailable', 'max_num_segments', 'only_expunge_deletes', - 'operation_threading', 'wait_for_merge') - def optimize(self, index=None, params=None): - """ - Explicitly optimize one or more indices through an API. - ``_ - - :arg index: A comma-separated list of index names; use `_all` or empty - string to perform the operation on all indices - :arg allow_no_indices: Whether to ignore if a wildcard indices - expression resolves into no concrete indices. (This includes `_all` - string or when no indices have been specified) - :arg expand_wildcards: Whether to expand wildcard expression to concrete - indices that are open, closed or both., default 'open', valid - choices are: 'open', 'closed', 'none', 'all' - :arg flush: Specify whether the index should be flushed after performing - the operation (default: true) - :arg ignore_unavailable: Whether specified concrete indices should be - ignored when unavailable (missing or closed) - :arg max_num_segments: The number of segments the index should be merged - into (default: dynamic) - :arg only_expunge_deletes: Specify whether the operation should only - expunge deleted documents - :arg operation_threading: TODO: ? - :arg wait_for_merge: Specify whether the request should block until the - merge process is finished (default: true) - """ - return self.transport.perform_request('POST', _make_path(index, - '_optimize'), params=params) - @query_params('allow_no_indices', 'analyze_wildcard', 'analyzer', 'default_operator', 'df', 'expand_wildcards', 'explain', 'ignore_unavailable', 'lenient', 'lowercase_expanded_terms', diff --git a/elasticsearch/client/ingest.py b/elasticsearch/client/ingest.py new file mode 100644 index 00000000..e5159579 --- /dev/null +++ b/elasticsearch/client/ingest.py @@ -0,0 +1,63 @@ +from .utils import NamespacedClient, query_params, _make_path, SKIP_IN_PATH + +class IngestClient(NamespacedClient): + @query_params('master_timeout') + def get_pipeline(self, id, params=None): + """ + ``_ + + :arg id: Comma separated list of pipeline ids. Wildcards supported + :arg master_timeout: Explicit operation timeout for connection to master + node + """ + if id in SKIP_IN_PATH: + raise ValueError("Empty value passed for a required argument 'id'.") + return self.transport.perform_request('GET', _make_path('_ingest', + 'pipeline', id), params=params) + + @query_params('master_timeout', 'timeout') + def put_pipeline(self, id, body, params=None): + """ + ``_ + + :arg id: Pipeline ID + :arg body: The ingest definition + :arg master_timeout: Explicit operation timeout for connection to master + node + :arg timeout: Explicit operation timeout + """ + for param in (id, body): + if param in SKIP_IN_PATH: + raise ValueError("Empty value passed for a required argument.") + return self.transport.perform_request('PUT', _make_path('_ingest', + 'pipeline', id), params=params, body=body) + + @query_params('master_timeout', 'timeout') + def delete_pipeline(self, id, params=None): + """ + ``_ + + :arg id: Pipeline ID + :arg master_timeout: Explicit operation timeout for connection to master + node + :arg timeout: Explicit operation timeout + """ + if id in SKIP_IN_PATH: + raise ValueError("Empty value passed for a required argument 'id'.") + return self.transport.perform_request('DELETE', _make_path('_ingest', + 'pipeline', id), params=params) + + @query_params('verbose') + def simulate(self, body, id=None, params=None): + """ + ``_ + + :arg body: The simulate definition + :arg id: Pipeline ID + :arg verbose: Verbose mode. Display data output for each processor in + executed pipeline, default False + """ + if body in SKIP_IN_PATH: + raise ValueError("Empty value passed for a required argument 'body'.") + return self.transport.perform_request('GET', _make_path('_ingest', + 'pipeline', id, '_simulate'), params=params, body=body) diff --git a/elasticsearch/client/tasks.py b/elasticsearch/client/tasks.py new file mode 100644 index 00000000..67d3d83f --- /dev/null +++ b/elasticsearch/client/tasks.py @@ -0,0 +1,45 @@ +from .utils import NamespacedClient, query_params, _make_path, SKIP_IN_PATH + +class TasksClient(NamespacedClient): + @query_params('actions', 'detailed', 'node_id', 'parent_node', + 'parent_task', 'wait_for_completion') + def list(self, task_id=None, params=None): + """ + ``_ + + :arg task_id: Return the task with specified id + :arg actions: A comma-separated list of actions that should be returned. + Leave empty to return all. + :arg detailed: Return detailed task information (default: false) + :arg node_id: A comma-separated list of node IDs or names to limit the + returned information; use `_local` to return information from the + node you're connecting to, leave empty to get information from all + nodes + :arg parent_node: Return tasks with specified parent node. + :arg parent_task: Return tasks with specified parent task id. Set to -1 + to return all. + :arg wait_for_completion: Wait for the matching tasks to complete + (default: false) + """ + return self.transport.perform_request('GET', _make_path('_tasks', + task_id), params=params) + + @query_params('actions', 'node_id', 'parent_node', 'parent_task') + def cancel(self, task_id=None, params=None): + """ + ``_ + + :arg task_id: Cancel the task with specified id + :arg actions: A comma-separated list of actions that should be + cancelled. Leave empty to cancel all. + :arg node_id: A comma-separated list of node IDs or names to limit the + returned information; use `_local` to return information from the + node you're connecting to, leave empty to get information from all + nodes + :arg parent_node: Cancel tasks with specified parent node. + :arg parent_task: Cancel tasks with specified parent task id. Set to -1 + to cancel all. + """ + return self.transport.perform_request('POST', _make_path('_tasks', + task_id, '_cancel'), params=params) + diff --git a/elasticsearch/helpers/__init__.py b/elasticsearch/helpers/__init__.py index 2f98ba7f..98bc0ef3 100644 --- a/elasticsearch/helpers/__init__.py +++ b/elasticsearch/helpers/__init__.py @@ -268,7 +268,8 @@ def scan(client, query=None, scroll='5m', raise_on_error=True, preserve_order=Fa """ if not preserve_order: - kwargs['search_type'] = 'scan' + body = query.copy() if query else {} + body["sort"] = "_doc" # initial search resp = client.search(body=query, scroll=scroll, **kwargs) @@ -279,7 +280,7 @@ def scan(client, query=None, scroll='5m', raise_on_error=True, preserve_order=Fa first_run = True while True: # if we didn't set search_type to scan initial search contains data - if preserve_order and first_run: + if first_run: first_run = False else: resp = client.scroll(scroll_id, scroll=scroll) diff --git a/setup.py b/setup.py index ede23a09..b51dcdb2 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import setup, find_packages import sys import os -VERSION = (2, 3, 0) +VERSION = (5, 0, 0, 'dev') __version__ = VERSION __versionstr__ = '.'.join(map(str, VERSION)) diff --git a/test_elasticsearch/test_server/test_common.py b/test_elasticsearch/test_server/test_common.py index 242034d7..a8ea5366 100644 --- a/test_elasticsearch/test_server/test_common.py +++ b/test_elasticsearch/test_server/test_common.py @@ -7,6 +7,7 @@ import re from os import walk, environ from os.path import exists, join, dirname, pardir import yaml +from shutil import rmtree from elasticsearch import TransportError from elasticsearch.compat import string_types @@ -48,6 +49,13 @@ class YamlTestCase(ElasticsearchTestCase): self.last_response = None self._state = {} + def tearDown(self): + super(YamlTestCase, self).tearDown() + for repo, definition in self.client.snapshot.get_repository(repository='_all').items(): + self.client.snapshot.delete_repository(repository=repo) + if definition['type'] == 'fs': + rmtree('/tmp/%s' % definition['settings']['location']) + def _resolve(self, value): # resolve variables if isinstance(value, string_types) and value.startswith('$'): diff --git a/test_elasticsearch/test_server/test_helpers.py b/test_elasticsearch/test_server/test_helpers.py index 95b29ae1..fc1f9b8c 100644 --- a/test_elasticsearch/test_server/test_helpers.py +++ b/test_elasticsearch/test_server/test_helpers.py @@ -191,7 +191,7 @@ class TestScan(ElasticsearchTestCase): bulk.append({"answer": x, "correct": x == 42}) self.client.bulk(bulk, refresh=True) - docs = list(helpers.scan(self.client, index="test_index", doc_type="answers", size=2, query={"sort": ["answer"]}, preserve_order=True)) + docs = list(helpers.scan(self.client, index="test_index", doc_type="answers", query={"sort": "answer"}, preserve_order=True)) self.assertEquals(100, len(docs)) self.assertEquals(list(map(str, range(100))), list(d['_id'] for d in docs)) @@ -229,7 +229,7 @@ class TestReindex(ElasticsearchTestCase): self.assertEquals({"answer": 42, "correct": True}, self.client.get(index="prod_index", doc_type="answers", id=42)['_source']) def test_reindex_accepts_a_query(self): - helpers.reindex(self.client, "test_index", "prod_index", query={"query": {"filtered": {"filter": {"term": {"_type": "answers"}}}}}) + helpers.reindex(self.client, "test_index", "prod_index", query={"query": {"bool": {"filter": {"term": {"_type": "answers"}}}}}) self.client.indices.refresh() self.assertTrue(self.client.indices.exists("prod_index"))