Skip to content

Commit dda122f

Browse files
authored
Change DslBase._clone to be shallow (#892)
* Change DslBase._clone to be shallow Fixes #885 * Add docs for the shallow copy change
1 parent e28d3ad commit dda122f

File tree

4 files changed

+12
-7
lines changed

4 files changed

+12
-7
lines changed

Changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Changelog
1212
a backwards incompatible change for custom aggregations that redefine that
1313
method.
1414
* ``DocType.update`` now supports ``refresh`` kwarg
15+
* ``DslBase._clone`` now produces a shallow copy, this means that modifying an
16+
existing query can have effects on existing ``Search`` objects.
1517

1618
6.1.0 (2018-01-09)
1719
------------------

docs/search_dsl.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ The ``Search`` object represents the entire search request:
2323

2424
The API is designed to be chainable. With the exception of the
2525
aggregations functionality this means that the ``Search`` object is immutable -
26-
all changes to the object will result in a copy being created which contains
27-
the changes. This means you can safely pass the ``Search`` object to foreign
28-
code without fear of it modifying your objects.
26+
all changes to the object will result in a shallow copy being created which
27+
contains the changes. This means you can safely pass the ``Search`` object to
28+
foreign code without fear of it modifying your objects as long as it sticks to
29+
the ``Search`` object APIs.
2930

3031
You can pass an instance of the low-level `elasticsearch client <https://elasticsearch-py.readthedocs.io/>`_ when
3132
instantiating the ``Search`` object:

elasticsearch_dsl/utils.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import unicode_literals
22

33
import collections
4+
from copy import copy
45

56
from six import iteritems, add_metaclass
67
from six.moves import map
@@ -198,7 +199,7 @@ class DslBase(object):
198199
199200
Provides several feature:
200201
- attribute access to the wrapped dictionary (.field instead of ['field'])
201-
- _clone method returning a deep copy of self
202+
- _clone method returning a copy of self
202203
- to_dict method to serialize into dict (to be sent via elasticsearch-py)
203204
- basic logical operators (&, | and ~) using a Bool(Filter|Query) TODO:
204205
move into a class specific for Query/Filter
@@ -330,8 +331,10 @@ def to_dict(self):
330331
return {self.name: d}
331332

332333
def _clone(self):
333-
return self._type_shortcut(self.to_dict())
334-
334+
c = self.__class__()
335+
for attr in self._params:
336+
c._params[attr] = copy(self._params[attr])
337+
return c
335338

336339
class ObjectBase(AttrDict):
337340
def __init__(self, **kwargs):

test_elasticsearch_dsl/test_query.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ def test_query_clone():
5252

5353
assert bool == bool_clone
5454
assert bool is not bool_clone
55-
assert bool.must[0] is not bool_clone.must[0]
5655

5756
def test_bool_converts_its_init_args_to_queries():
5857
q = query.Bool(must=[{"match": {"f": "value"}}])

0 commit comments

Comments
 (0)