diff --git a/docs/source/reference/pandagg.agg.rst b/docs/source/reference/pandagg.agg.rst deleted file mode 100644 index 3a896741..00000000 --- a/docs/source/reference/pandagg.agg.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.agg module -================== - -.. automodule:: pandagg.agg - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.client.rst b/docs/source/reference/pandagg.client.rst deleted file mode 100644 index 4c70082a..00000000 --- a/docs/source/reference/pandagg.client.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.client module -===================== - -.. automodule:: pandagg.client - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.interactive.abstract.rst b/docs/source/reference/pandagg.interactive.abstract.rst deleted file mode 100644 index 9c6710fa..00000000 --- a/docs/source/reference/pandagg.interactive.abstract.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.interactive.abstract module -=================================== - -.. automodule:: pandagg.interactive.abstract - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.interactive.client.rst b/docs/source/reference/pandagg.interactive.client.rst deleted file mode 100644 index 910fd0ce..00000000 --- a/docs/source/reference/pandagg.interactive.client.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.interactive.client module -================================= - -.. automodule:: pandagg.interactive.client - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.interactive.index.rst b/docs/source/reference/pandagg.interactive.index.rst deleted file mode 100644 index 9f8a9c8c..00000000 --- a/docs/source/reference/pandagg.interactive.index.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.interactive.index module -================================ - -.. automodule:: pandagg.interactive.index - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.agg.abstract.rst b/docs/source/reference/pandagg.node.agg.abstract.rst deleted file mode 100644 index 20ed2e40..00000000 --- a/docs/source/reference/pandagg.node.agg.abstract.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.node.agg.abstract module -================================ - -.. automodule:: pandagg.node.agg.abstract - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.agg.bucket.rst b/docs/source/reference/pandagg.node.agg.bucket.rst deleted file mode 100644 index 48e3ed41..00000000 --- a/docs/source/reference/pandagg.node.agg.bucket.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.node.agg.bucket module -============================== - -.. automodule:: pandagg.node.agg.bucket - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.agg.deserializer.rst b/docs/source/reference/pandagg.node.agg.deserializer.rst deleted file mode 100644 index fcd2acc7..00000000 --- a/docs/source/reference/pandagg.node.agg.deserializer.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.node.agg.deserializer module -==================================== - -.. automodule:: pandagg.node.agg.deserializer - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.agg.metric.rst b/docs/source/reference/pandagg.node.agg.metric.rst deleted file mode 100644 index 14771923..00000000 --- a/docs/source/reference/pandagg.node.agg.metric.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.node.agg.metric module -============================== - -.. automodule:: pandagg.node.agg.metric - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.agg.pipeline.rst b/docs/source/reference/pandagg.node.agg.pipeline.rst deleted file mode 100644 index 08651f5f..00000000 --- a/docs/source/reference/pandagg.node.agg.pipeline.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.node.agg.pipeline module -================================ - -.. automodule:: pandagg.node.agg.pipeline - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.agg.rst b/docs/source/reference/pandagg.node.agg.rst deleted file mode 100644 index 2e585566..00000000 --- a/docs/source/reference/pandagg.node.agg.rst +++ /dev/null @@ -1,21 +0,0 @@ -pandagg.node.agg package -======================== - -Submodules ----------- - -.. toctree:: - :maxdepth: 8 - - pandagg.node.agg.abstract - pandagg.node.agg.bucket - pandagg.node.agg.metric - pandagg.node.agg.pipeline - -Module contents ---------------- - -.. automodule:: pandagg.node.agg - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.mapping.deserializer.rst b/docs/source/reference/pandagg.node.mapping.deserializer.rst deleted file mode 100644 index 5dcbf7b6..00000000 --- a/docs/source/reference/pandagg.node.mapping.deserializer.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.node.mapping.deserializer module -======================================== - -.. automodule:: pandagg.node.mapping.deserializer - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.mixins.rst b/docs/source/reference/pandagg.node.mixins.rst deleted file mode 100644 index b3d0927e..00000000 --- a/docs/source/reference/pandagg.node.mixins.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.node.mixins module -========================== - -.. automodule:: pandagg.node.mixins - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.node.query.deserializer.rst b/docs/source/reference/pandagg.node.query.deserializer.rst deleted file mode 100644 index d2ade350..00000000 --- a/docs/source/reference/pandagg.node.query.deserializer.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.node.query.deserializer module -====================================== - -.. automodule:: pandagg.node.query.deserializer - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/reference/pandagg.tree.agg.rst b/docs/source/reference/pandagg.tree.agg.rst deleted file mode 100644 index a0e16fe3..00000000 --- a/docs/source/reference/pandagg.tree.agg.rst +++ /dev/null @@ -1,7 +0,0 @@ -pandagg.tree.agg module -======================= - -.. automodule:: pandagg.tree.agg - :members: - :undoc-members: - :show-inheritance: diff --git a/pandagg/node/aggs/abstract.py b/pandagg/node/aggs/abstract.py index dd9af88e..db1a5ea1 100644 --- a/pandagg/node/aggs/abstract.py +++ b/pandagg/node/aggs/abstract.py @@ -103,11 +103,13 @@ def _type_deserializer(cls, name_or_agg, **params): if not isinstance(name_or_agg, string_types): raise ValueError("Invalid") # "tags", size=10 (by default apply a terms agg) - if "name" not in params: + if "name" not in params and "field" not in params: return cls.get_dsl_class("terms")( name=name_or_agg, field=name_or_agg, **params ) # "terms", field="tags", name="per_tags" + if "name" not in params: + raise ValueError("Aggregation expects a 'name'. Got %s." % params) return cls.get_dsl_class(name_or_agg)(**params) def line_repr(self, depth, **kwargs): diff --git a/pandagg/search.py b/pandagg/search.py index 9bf9ee16..478986ff 100644 --- a/pandagg/search.py +++ b/pandagg/search.py @@ -118,36 +118,50 @@ def query(self, *args, **kwargs): s._query = s._query.query(*args, **kwargs) return s + query.__doc__ = Query.query.__doc__ + def filter(self, *args, **kwargs): s = self._clone() s._query = s._query.filter(*args, **kwargs) return s + filter.__doc__ = Query.filter.__doc__ + def must_not(self, *args, **kwargs): s = self._clone() s._query = s._query.must_not(*args, **kwargs) return s + must_not.__doc__ = Query.must_not.__doc__ + def should(self, *args, **kwargs): s = self._clone() s._query = s._query.should(*args, **kwargs) return s + should.__doc__ = Query.should.__doc__ + def must(self, *args, **kwargs): s = self._clone() s._query = s._query.must(*args, **kwargs) return s + must.__doc__ = Query.must.__doc__ + def aggs(self, *args, **kwargs): s = self._clone() s._aggs = s._aggs.aggs(*args, **kwargs) return s + aggs.__doc__ = Aggs.aggs.__doc__ + def groupby(self, *args, **kwargs): s = self._clone() s._aggs = s._aggs.groupby(*args, **kwargs) return s + groupby.__doc__ = Aggs.groupby.__doc__ + def __iter__(self): """ Iterate over the hits. diff --git a/pandagg/tree/aggs.py b/pandagg/tree/aggs.py index 7ca1a795..a1ef7803 100644 --- a/pandagg/tree/aggs.py +++ b/pandagg/tree/aggs.py @@ -3,8 +3,8 @@ from __future__ import unicode_literals +import json -from builtins import str as text from future.utils import python_2_unicode_compatible from pandagg.tree._tree import Tree @@ -120,7 +120,6 @@ def _validate_aggs_parent_id(self, pid): return pid leaves = self.leaves(id_only=False) # root - # TODO if len(leaves) == 0: return None @@ -132,8 +131,7 @@ def _validate_aggs_parent_id(self, pid): return leaves[0].identifier def groupby(self, *args, **kwargs): - """Arrange passed aggregations in `by` arguments "vertically" (nested manner), above or below another agg - clause. + r"""Arrange passed aggregations in vertical/nested manner, above or below another agg clause. Given the initial aggregation:: @@ -164,10 +162,48 @@ def groupby(self, *args, **kwargs): A──> B : KO, ambiguous, must precise either A, B or C └──> C - :param by: aggregation(s) clauses to insert "vertically" - :param insert_below: parent aggregation id under which these aggregations should be placed - :param insert_above: aggregation id above which these aggregations should be placed - :param kwargs: agg body arguments when using "string" syntax for terms aggregation + + Accepted declarations for single aggregation: + + Official DSL like: + + >>> Aggs().groupby('terms', name='per_user_id', field='user_id') + {"terms_on_my_field":{"terms":{"field":"some_field"}}} + + Passing a dict: + + >>> Aggs().groupby({"terms_on_my_field":{"terms":{"field":"some_field"}}}) + {"terms_on_my_field":{"terms":{"field":"some_field"}}} + + + Using DSL class: + + >>> from pandagg.aggs import Terms + >>> Aggs().groupby(Terms('terms_on_my_field', field='some_field')) + {"terms_on_my_field":{"terms":{"field":"some_field"}}} + + Shortcut syntax for terms aggregation: creates a terms aggregation, using field as aggregation name + + >>> Aggs().groupby('some_field') + {"some_field":{"terms":{"field":"some_field"}}} + + Using a Aggs object: + + >>> Aggs().groupby(Aggs('terms', name='per_user_id', field='user_id')) + {"terms_on_my_field":{"terms":{"field":"some_field"}}} + + Accepted declarations for multiple aggregations: + + + :Keyword Arguments: + * *insert_below* (``string``) -- + Parent aggregation name under which these aggregations should be placed + * *insert_above* (``string``) -- + Aggregation name above which these aggregations should be placed + + * remaining kwargs: + Used as body in aggregation + :rtype: pandagg.aggs.Aggs """ insert_below = kwargs.pop("insert_below", None) @@ -182,12 +218,16 @@ def groupby(self, *args, **kwargs): # groupby({}, {}) if len(args) > 1: if kwargs: - raise ValueError() + raise ValueError( + "Kwargs not allowed when passing multiple aggregations in args." + ) inserted_aggs = [self.deserialize(arg) for arg in args] # groupby([{}, {}]) elif len(args) == 1 and isinstance(args[0], (list, tuple)): if kwargs: - raise ValueError() + raise ValueError( + "Kwargs not allowed when passing multiple aggregations in args." + ) inserted_aggs = [self.deserialize(arg) for arg in args[0]] # groupby({}) # groupby(Terms()) @@ -378,4 +418,4 @@ def _insert_node_below(self, node, parent_id, with_children=True): ) def __str__(self): - return "\n%s" % text(self.show()) + return json.dumps(self.to_dict(), indent=2) diff --git a/tests/testing_samples/data_sample.py b/tests/testing_samples/data_sample.py index a7ce3554..d1631b8b 100644 --- a/tests/testing_samples/data_sample.py +++ b/tests/testing_samples/data_sample.py @@ -11,13 +11,6 @@ from tests.testing_samples.mapping_example import MAPPING -EXPECTED_REPR = """ -[classification_type] terms -└── [global_metrics.field.name] terms - ├── [avg_f1_micro] avg - └── [avg_nb_classes] avg -""" - EXPECTED_AGG_QUERY = { "classification_type": { "aggs": { diff --git a/tests/tree/test_aggs.py b/tests/tree/test_aggs.py index 27ce618f..cb6dd190 100644 --- a/tests/tree/test_aggs.py +++ b/tests/tree/test_aggs.py @@ -14,7 +14,6 @@ AbsentMappingFieldError, InvalidOperationMappingFieldError, ) -from pandagg.tree.mapping import Mapping from pandagg.node.aggs.bucket import DateHistogram, Terms, Filter from pandagg.node.aggs.metric import Avg, Min @@ -129,12 +128,24 @@ def test_add_node_with_mapping(self): ) self.assertEqual(len(with_mapping.list()), 3) self.assertEqual( - with_mapping.__str__(), - """ -[workflow] terms -└── [nested_below_workflow] nested - └── [local_f1_score] avg -""", + with_mapping.to_dict(), + { + "workflow": { + "aggs": { + "nested_below_workflow": { + "aggs": { + "local_f1_score": { + "avg": { + "field": "local_metrics.performance.test.f1_score" + } + } + }, + "nested": {"path": "local_metrics"}, + } + }, + "terms": {"field": "workflow"}, + } + }, ) self.assertIn("nested_below_workflow", with_mapping) nested_node = with_mapping.get("nested_below_workflow") @@ -149,13 +160,29 @@ def test_add_node_with_mapping(self): parent_id="workflow", ) self.assertEqual( - with_mapping.__str__(), - """ -[workflow] terms -└── [nested_below_workflow] nested - ├── [local_f1_score] avg - └── [local_precision] avg -""", + with_mapping.to_dict(), + { + "workflow": { + "aggs": { + "nested_below_workflow": { + "aggs": { + "local_f1_score": { + "avg": { + "field": "local_metrics.performance.test.f1_score" + } + }, + "local_precision": { + "avg": { + "field": "local_metrics.performance.test.precision" + } + }, + }, + "nested": {"path": "local_metrics"}, + } + }, + "terms": {"field": "workflow"}, + } + }, ) self.assertEqual(len(with_mapping.list()), 4) @@ -167,15 +194,37 @@ def test_add_node_with_mapping(self): ) self.assertEqual(len(with_mapping.list()), 6) self.assertEqual( - with_mapping.__str__(), - """ -[workflow] terms -└── [nested_below_workflow] nested - ├── [local_f1_score] avg - ├── [local_precision] avg - └── [reverse_nested_below_nested_below_workflow] reverse_nested - └── [language_terms] terms -""", + with_mapping.to_dict(), + { + "workflow": { + "aggs": { + "nested_below_workflow": { + "aggs": { + "local_f1_score": { + "avg": { + "field": "local_metrics.performance.test.f1_score" + } + }, + "local_precision": { + "avg": { + "field": "local_metrics.performance.test.precision" + } + }, + "reverse_nested_below_nested_below_workflow": { + "aggs": { + "language_terms": { + "terms": {"field": "language"} + } + }, + "reverse_nested": {}, + }, + }, + "nested": {"path": "local_metrics"}, + } + }, + "terms": {"field": "workflow"}, + } + }, ) def test_add_node_without_mapping(self): @@ -230,12 +279,29 @@ def test_paste_tree_with_mapping(self): {"week", "nested_below_week", "local_metrics.field_class.name"}, ) self.assertEqual( - initial_agg_1.__str__(), - """ -[week] date_histogram -└── [nested_below_week] nested - └── [local_metrics.field_class.name] terms -""", + initial_agg_1.to_dict(), + { + "week": { + "date_histogram": { + "field": "date", + "format": "yyyy-MM-dd", + "interval": "1w", + }, + "aggs": { + "nested_below_week": { + "nested": {"path": "local_metrics"}, + "aggs": { + "local_metrics.field_class.name": { + "terms": { + "field": "local_metrics.field_class.name", + "size": 10, + } + } + }, + } + }, + } + }, ) # without explicit nested @@ -269,12 +335,29 @@ def test_paste_tree_with_mapping(self): {"week", "nested_below_week", "local_metrics.field_class.name"}, ) self.assertEqual( - initial_agg_2.__str__(), - """ -[week] date_histogram -└── [nested_below_week] nested - └── [local_metrics.field_class.name] terms -""", + initial_agg_2.to_dict(), + { + "week": { + "date_histogram": { + "field": "date", + "format": "yyyy-MM-dd", + "interval": "1w", + }, + "aggs": { + "nested_below_week": { + "nested": {"path": "local_metrics"}, + "aggs": { + "local_metrics.field_class.name": { + "terms": { + "field": "local_metrics.field_class.name", + "size": 10, + } + } + }, + } + }, + } + }, ) def test_insert_tree_without_mapping(self): @@ -289,7 +372,6 @@ def test_insert_tree_without_mapping(self): } } }, - mapping=None, ) self.assertEqual({n.identifier for n in initial_agg_1.list()}, {"week"}) @@ -319,50 +401,29 @@ def test_insert_tree_without_mapping(self): {"week", "nested_below_week", "local_metrics.field_class.name"}, ) self.assertEqual( - initial_agg_1.__str__(), - """ -[week] date_histogram -└── [nested_below_week] nested - └── [local_metrics.field_class.name] terms -""", - ) - - # without explicit nested (will NOT add nested) - initial_agg_2 = Aggs( + initial_agg_1.to_dict(), { "week": { "date_histogram": { "field": "date", "format": "yyyy-MM-dd", "interval": "1w", - } + }, + "aggs": { + "nested_below_week": { + "nested": {"path": "local_metrics"}, + "aggs": { + "local_metrics.field_class.name": { + "terms": { + "field": "local_metrics.field_class.name", + "size": 10, + } + } + }, + } + }, } }, - mapping=None, - ) - self.assertEqual(to_id_set(initial_agg_2.list()), {"week"}) - - pasted_agg_2 = Aggs( - { - "local_metrics.field_class.name": { - "terms": {"field": "local_metrics.field_class.name", "size": 10} - } - } - ) - self.assertEqual( - to_id_set(pasted_agg_2.list()), {"local_metrics.field_class.name"} - ) - - initial_agg_2.insert_tree(pasted_agg_2, "week") - self.assertEqual( - to_id_set(initial_agg_2.list()), {"week", "local_metrics.field_class.name"} - ) - self.assertEqual( - initial_agg_2.__str__(), - """ -[week] date_histogram -└── [local_metrics.field_class.name] terms -""", ) def test_interpret_agg_string(self): @@ -457,46 +518,6 @@ def test_interpret_node(self): }, ) - def test_query_dict(self): - # empty - self.assertEqual(Aggs().to_dict(), {}) - - # single node - agg = Aggs() - node = Terms(name="root_agg", field="some_field", size=10) - agg.insert_node(node) - self.assertEqual( - agg.to_dict(), {"root_agg": {"terms": {"field": "some_field", "size": 10}}}, - ) - - # hierarchy - agg.insert_node( - Terms(name="other_name", field="other_field", size=30), "root_agg" - ) - agg.insert_node( - Avg(name="avg_some_other_field", field="some_other_field"), "root_agg" - ) - self.assertEqual( - agg.__str__(), - """ -[root_agg] terms -├── [avg_some_other_field] avg -└── [other_name] terms -""", - ) - self.assertEqual( - agg.to_dict(), - { - "root_agg": { - "aggs": { - "avg_some_other_field": {"avg": {"field": "some_other_field"}}, - "other_name": {"terms": {"field": "other_field", "size": 30}}, - }, - "terms": {"field": "some_field", "size": 10}, - } - }, - ) - def test_validate_aggs_parent_id(self): """ @@ -552,36 +573,11 @@ def test_validate_aggs_parent_id(self): # TODO - pipeline aggregation under metric agg - def test_agg_method(self): - pass - - def test_groupby_method(self): - pass - - def test_mapping_from_init(self): - agg_from_dict_mapping = Aggs(mapping=MAPPING) - agg_from_tree_mapping = Aggs(mapping=Mapping(MAPPING)) - self.assertIsInstance(agg_from_dict_mapping, Aggs) - self.assertIsInstance(agg_from_tree_mapping, Aggs) - self.assertEqual( - agg_from_dict_mapping.mapping.__repr__(), - agg_from_tree_mapping.mapping.__repr__(), - ) - self.assertEqual( - agg_from_dict_mapping.to_dict(), agg_from_tree_mapping.to_dict() - ) - - def test_init_from_dict(self): - my_agg = Aggs(sample.EXPECTED_AGG_QUERY, mapping=MAPPING) - self.assertEqual(my_agg.to_dict(), sample.EXPECTED_AGG_QUERY) - self.assertEqual(my_agg.__str__(), sample.EXPECTED_REPR) - def test_init_from_node_hierarchy(self): node_hierarchy = sample.get_node_hierarchy() agg = Aggs(node_hierarchy, mapping=MAPPING) self.assertEqual(agg.to_dict(), sample.EXPECTED_AGG_QUERY) - self.assertEqual(agg.__str__(), sample.EXPECTED_REPR) # with nested node_hierarchy = DateHistogram( @@ -632,65 +628,119 @@ def test_init_from_node_hierarchy(self): }, ) self.assertEqual( - agg.__str__(), - """ -[week] date_histogram -└── [nested_below_week] nested - └── [local_metrics.field_class.name] terms - └── [min_f1_score] min -""", + agg.to_dict(), + { + "week": { + "aggs": { + "nested_below_week": { + "aggs": { + "local_metrics.field_class.name": { + "aggs": { + "min_f1_score": { + "min": { + "field": "local_metrics.performance.test.f1_score" + } + } + }, + "terms": { + "field": "local_metrics.field_class.name", + "size": 10, + }, + } + }, + "nested": {"path": "local_metrics"}, + } + }, + "date_histogram": {"field": "date", "interval": "1w"}, + } + }, ) - def test_groupby_and_agg(self): + def test_agg_init(self): agg = sample.get_wrapper_declared_agg() self.assertEqual(agg.to_dict(), sample.EXPECTED_AGG_QUERY) - self.assertEqual(agg.__str__(), sample.EXPECTED_REPR) def test_groupby_insert_below(self): a1 = Aggs( Terms("A", field="A", aggs=[Terms("B", field="B"), Terms("C", field="C")]) ) self.assertEqual( - a1.__repr__(), - """ -[A] terms -├── [B] terms -└── [C] terms -""", + a1.to_dict(), + { + "A": { + "terms": {"field": "A"}, + "aggs": { + "C": {"terms": {"field": "C"}}, + "B": {"terms": {"field": "B"}}, + }, + } + }, ) self.assertEqual( - a1.groupby(Terms("D", field="D"), insert_below="A").__repr__(), - """ -[A] terms -└── [D] terms - ├── [B] terms - └── [C] terms -""", + a1.groupby(Terms("D", field="D"), insert_below="A").to_dict(), + { + "A": { + "terms": {"field": "A"}, + "aggs": { + "D": { + "terms": {"field": "D"}, + "aggs": { + "B": {"terms": {"field": "B"}}, + "C": {"terms": {"field": "C"}}, + }, + } + }, + } + }, ) self.assertEqual( a1.groupby( [Terms("D", field="D"), Terms("E", field="E")], insert_below="A" - ).__repr__(), - """ -[A] terms -└── [D] terms - └── [E] terms - ├── [B] terms - └── [C] terms -""", + ).to_dict(), + { + "A": { + "terms": {"field": "A"}, + "aggs": { + "D": { + "terms": {"field": "D"}, + "aggs": { + "E": { + "terms": {"field": "E"}, + "aggs": { + "C": {"terms": {"field": "C"}}, + "B": {"terms": {"field": "B"}}, + }, + } + }, + } + }, + } + }, ) self.assertEqual( a1.groupby( Terms("D", field="D", aggs=Terms("E", field="E")), insert_below="A" - ).__repr__(), - """ -[A] terms -└── [D] terms - └── [E] terms - ├── [B] terms - └── [C] terms -""", + ).to_dict(), + { + "A": { + "terms": {"field": "A"}, + "aggs": { + "D": { + "terms": {"field": "D"}, + "aggs": { + "E": { + "terms": {"field": "E"}, + "aggs": { + "B": {"terms": {"field": "B"}}, + "C": {"terms": {"field": "C"}}, + }, + } + }, + } + }, + } + }, ) def test_groupby_insert_above(self): @@ -698,59 +748,101 @@ def test_groupby_insert_above(self): Terms("A", field="A", aggs=[Terms("B", field="B"), Terms("C", field="C")]) ) self.assertEqual( - a1.__repr__(), - """ -[A] terms -├── [B] terms -└── [C] terms -""", + a1.to_dict(), + { + "A": { + "terms": {"field": "A"}, + "aggs": { + "B": {"terms": {"field": "B"}}, + "C": {"terms": {"field": "C"}}, + }, + } + }, ) self.assertEqual( - a1.groupby(Terms("D", field="D"), insert_above="B").__repr__(), - """ -[A] terms -├── [C] terms -└── [D] terms - └── [B] terms -""", + a1.groupby(Terms("D", field="D"), insert_above="B").to_dict(), + { + "A": { + "terms": {"field": "A"}, + "aggs": { + "C": {"terms": {"field": "C"}}, + "D": { + "terms": {"field": "D"}, + "aggs": {"B": {"terms": {"field": "B"}}}, + }, + }, + } + }, ) self.assertEqual( a1.groupby( [Terms("D", field="D"), Terms("E", field="E")], insert_above="B" - ).__repr__(), - """ -[A] terms -├── [C] terms -└── [D] terms - └── [E] terms - └── [B] terms -""", + ).to_dict(), + { + "A": { + "terms": {"field": "A"}, + "aggs": { + "C": {"terms": {"field": "C"}}, + "D": { + "terms": {"field": "D"}, + "aggs": { + "E": { + "terms": {"field": "E"}, + "aggs": {"B": {"terms": {"field": "B"}}}, + } + }, + }, + }, + } + }, ) self.assertEqual( a1.groupby( Terms("D", field="D", aggs=Terms("E", field="E")), insert_above="B" - ).__repr__(), - """ -[A] terms -├── [C] terms -└── [D] terms - └── [E] terms - └── [B] terms -""", + ).to_dict(), + { + "A": { + "aggs": { + "C": {"terms": {"field": "C"}}, + "D": { + "aggs": { + "E": { + "aggs": {"B": {"terms": {"field": "B"}}}, + "terms": {"field": "E"}, + } + }, + "terms": {"field": "D"}, + }, + }, + "terms": {"field": "A"}, + } + }, ) # above root self.assertEqual( a1.groupby( Terms("D", field="D", aggs=Terms("E", field="E")), insert_above="A" - ).__repr__(), - """ -[D] terms -└── [E] terms - └── [A] terms - ├── [B] terms - └── [C] terms -""", + ).to_dict(), + { + "D": { + "terms": {"field": "D"}, + "aggs": { + "E": { + "terms": {"field": "E"}, + "aggs": { + "A": { + "terms": {"field": "A"}, + "aggs": { + "B": {"terms": {"field": "B"}}, + "C": {"terms": {"field": "C"}}, + }, + } + }, + } + }, + } + }, ) def test_agg_insert_below(self): @@ -758,34 +850,46 @@ def test_agg_insert_below(self): Terms("A", field="A", aggs=[Terms("B", field="B"), Terms("C", field="C")]) ) self.assertEqual( - a1.__repr__(), - """ -[A] terms -├── [B] terms -└── [C] terms -""", + a1.to_dict(), + { + "A": { + "terms": {"field": "A"}, + "aggs": { + "C": {"terms": {"field": "C"}}, + "B": {"terms": {"field": "B"}}, + }, + } + }, ) self.assertEqual( - a1.aggs(Terms("D", field="D"), insert_below="A").__repr__(), - """ -[A] terms -├── [B] terms -├── [C] terms -└── [D] terms -""", + a1.aggs(Terms("D", field="D"), insert_below="A").to_dict(), + { + "A": { + "aggs": { + "B": {"terms": {"field": "B"}}, + "C": {"terms": {"field": "C"}}, + "D": {"terms": {"field": "D"}}, + }, + "terms": {"field": "A"}, + } + }, ) self.assertEqual( a1.aggs( [Terms("D", field="D"), Terms("E", field="E")], insert_below="A" - ).__repr__(), - """ -[A] terms -├── [B] terms -├── [C] terms -├── [D] terms -└── [E] terms -""", + ).to_dict(), + { + "A": { + "aggs": { + "B": {"terms": {"field": "B"}}, + "C": {"terms": {"field": "C"}}, + "D": {"terms": {"field": "D"}}, + "E": {"terms": {"field": "E"}}, + }, + "terms": {"field": "A"}, + } + }, ) def test_applied_nested_path_at_node(self):