From ff4dddf3a4016bb8da75f43830a6616b7e31ee2f Mon Sep 17 00:00:00 2001 From: Casper Welzel Andersen Date: Fri, 8 Nov 2019 11:47:02 +0100 Subject: [PATCH 1/4] Remove unused QB methods/functions --- aiida/orm/querybuilder.py | 71 --------------------------------------- 1 file changed, 71 deletions(-) diff --git a/aiida/orm/querybuilder.py b/aiida/orm/querybuilder.py index 32193618dc..c1d2cdd230 100644 --- a/aiida/orm/querybuilder.py +++ b/aiida/orm/querybuilder.py @@ -1710,32 +1710,6 @@ def _get_connecting_node(self, index, joining_keyword=None, joining_value=None, self.tag_to_alias_map.keys())) return returnval - def _get_json_compatible(self, inp): - """ - - :param inp: - The input value that will be converted. - Recurses into each value if **inp** is an iterable. - """ - from aiida import orm - - if isinstance(inp, dict): - for key, val in inp.items(): - inp[self._get_json_compatible(key)] = self._get_json_compatible(inp.pop(key)) - elif isinstance(inp, (list, tuple)): - inp = [self._get_json_compatible(val) for val in inp] - elif inspect_isclass(inp): - if issubclass(inp, self.AiidaNode): - return '.'.join(inp._plugin_type_string.strip('.').split('.')[:-1]) - elif issubclass(inp, orm.Group): - return 'group' - else: - raise InputValidationError - else: - raise ValueError('unsupported type {} for input value'.format(type(inp))) - - return inp - def get_json_compatible_queryhelp(self): """ Makes the queryhelp a json-compatible dictionary. @@ -1921,51 +1895,6 @@ def _build(self): return self._query - def except_if_input_to(self, calc_class): - """ - Makes counterquery based on the own path, only selecting - entries that have been input to *calc_class* - - :param calc_class: The calculation class to check against - - :returns: self - """ - - def build_counterquery(calc_class): - if issubclass(calc_class, self.Node): - orm_calc_class = calc_class - type_spec = None - elif issubclass(calc_class, self.AiidaNode): - orm_calc_class = self.Node - type_spec = calc_class._plugin_type_string - else: - raise Exception('You have given me {}\n' - 'of type {}\n' - "and I don't know what to do with that" - ''.format(calc_class, type(calc_class))) - - input_alias_list = [] - for node in self._path: - tag = node['tag'] - requested_cols = [key for item in self._projections[tag] for key in item.keys()] - if '*' in requested_cols: - input_alias_list.append(aliased(self.tag_to_alias_map[tag])) - - counterquery = self._imp._get_session().query(orm_calc_class) - if type_spec: - counterquery = counterquery.filter(orm_calc_class.entity_type == type_spec) - for alias in input_alias_list: - link = aliased(self.Link) - counterquery = counterquery.join(link, orm_calc_class.id == link.output_id).join( - alias, alias.id == link.input_id) - counterquery = counterquery.add_entity(alias) - counterquery._entities.pop(0) - return counterquery - - self._query = self.get_query() - self._query = self._query.except_(build_counterquery(calc_class)) - return self - def get_aliases(self): """ :returns: the list of aliases From cc8bbc2e4db6a4855b30cc15bd4accc0218ffc9b Mon Sep 17 00:00:00 2001 From: Casper Welzel Andersen Date: Mon, 11 Nov 2019 12:34:19 +0100 Subject: [PATCH 2/4] Deprecate get_json_compatible_queryhelp in QB --- aiida/orm/querybuilder.py | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/aiida/orm/querybuilder.py b/aiida/orm/querybuilder.py index 8beff44715..a50748037e 100644 --- a/aiida/orm/querybuilder.py +++ b/aiida/orm/querybuilder.py @@ -26,8 +26,9 @@ from inspect import isclass as inspect_isclass import copy import logging +import warnings import six -from six.moves import range, zip +from six.moves import range from sqlalchemy import and_, or_, not_, func as sa_func, select, join from sqlalchemy.types import Integer from sqlalchemy.orm import aliased @@ -39,6 +40,7 @@ from aiida.common.links import LinkType from aiida.manage.manager import get_manager from aiida.common.exceptions import ConfigurationError +from aiida.common.warnings import AiidaDeprecationWarning from . import authinfos from . import comments @@ -1730,15 +1732,12 @@ def get_json_compatible_queryhelp(self): qb.all()==qb2.all() :returns: the json-compatible queryhelp + + .. deprecated:: 1.0.0 + Will be removed in `v2.0.0`, use the :meth:`.queryhelp` property instead. """ - return copy.deepcopy({ - 'path': self._path, - 'filters': self._filters, - 'project': self._projections, - 'order_by': self._order_by, - 'limit': self._limit, - 'offset': self._offset, - }) + warnings.warn('method is deprecated, use the `queryhelp` property instead', AiidaDeprecationWarning) + return self.queryhelp @property def queryhelp(self): @@ -1747,11 +1746,25 @@ def queryhelp(self): The queryhelp can be used to create a copy of the QueryBuilder instance like so:: qb = QueryBuilder(limit=3).append(StructureData, project='id').order_by({StructureData:'id'}) - qb2=QueryBuilder(**qb.queryhelp) + qb2 = QueryBuilder(**qb.queryhelp) + + This is a json-comptible dictionary. + In this way, the queryhelp can be stored in the database or a json-object, retrieved or shared and used later. + The following is True if no change has been made to the database:: - :return: a queryhelp dictionary + # Note that such a comparison can only be True if the order of results is enforced + qb.all() == qb2.all() + + :return: a json-compatible queryhelp dictionary """ - return self.get_json_compatible_queryhelp() + return copy.deepcopy({ + 'path': self._path, + 'filters': self._filters, + 'project': self._projections, + 'order_by': self._order_by, + 'limit': self._limit, + 'offset': self._offset, + }) def __deepcopy__(self, memo): """Create deep copy of QueryBuilder instance.""" From 1b1349ff65836c22ad28e5dcd780b0f3d03eb0ce Mon Sep 17 00:00:00 2001 From: Casper Welzel Andersen Date: Mon, 11 Nov 2019 14:11:21 +0100 Subject: [PATCH 3/4] Fix docstrings and use queryhelp in tests --- aiida/backends/tests/orm/test_querybuilder.py | 4 ++-- aiida/orm/querybuilder.py | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/aiida/backends/tests/orm/test_querybuilder.py b/aiida/backends/tests/orm/test_querybuilder.py index 2b6c7906e9..77694fdcb3 100644 --- a/aiida/backends/tests/orm/test_querybuilder.py +++ b/aiida/backends/tests/orm/test_querybuilder.py @@ -601,7 +601,7 @@ def test_direction_keyword(self): qb.append(orm.Data, with_incoming='c1', tag='d2or4') qb.append(orm.CalculationNode, tag='c2', with_incoming='d2or4') qb.append(orm.Data, tag='d3', with_incoming='c2', project='id') - qh = qb.get_json_compatible_queryhelp() # saving query for later + qh = qb.queryhelp # saving query for later qb.append(orm.Data, direction=-4, project='id') res1 = {item[1] for item in qb.all()} self.assertEqual(res1, {d1.id}) @@ -658,7 +658,7 @@ def test_queryhelp(self): qb.append(cls, filters={'attributes.foo-qh2': 'bar'}, subclassing=subclassing, project='uuid') self.assertEqual(qb.count(), expected_count) - qh = qb.get_json_compatible_queryhelp() + qh = qb.queryhelp qb_new = orm.QueryBuilder(**qh) self.assertEqual(qb_new.count(), expected_count) self.assertEqual(sorted([uuid for uuid, in qb.all()]), sorted([uuid for uuid, in qb_new.all()])) diff --git a/aiida/orm/querybuilder.py b/aiida/orm/querybuilder.py index a50748037e..c33a805c0e 100644 --- a/aiida/orm/querybuilder.py +++ b/aiida/orm/querybuilder.py @@ -1734,7 +1734,7 @@ def get_json_compatible_queryhelp(self): :returns: the json-compatible queryhelp .. deprecated:: 1.0.0 - Will be removed in `v2.0.0`, use the :meth:`.queryhelp` property instead. + Will be removed in `v2.0.0`, use the :meth:`aiida.orm.querybuilder.QueryBuilder.queryhelp` property instead. """ warnings.warn('method is deprecated, use the `queryhelp` property instead', AiidaDeprecationWarning) return self.queryhelp @@ -1748,10 +1748,7 @@ def queryhelp(self): qb = QueryBuilder(limit=3).append(StructureData, project='id').order_by({StructureData:'id'}) qb2 = QueryBuilder(**qb.queryhelp) - This is a json-comptible dictionary. - In this way, the queryhelp can be stored in the database or a json-object, retrieved or shared and used later. - The following is True if no change has been made to the database:: - + # The following is True if no change has been made to the database. # Note that such a comparison can only be True if the order of results is enforced qb.all() == qb2.all() @@ -1976,7 +1973,7 @@ def get_query(self): # The queryhelp_hash is used to determine # whether the query is still valid - queryhelp_hash = make_hash(self.get_json_compatible_queryhelp()) + queryhelp_hash = make_hash(self.queryhelp) # if self._hash (which is None if this function has not been invoked # and is a string (hash) if it has) is the same as the queryhelp # I can use the query again: From 246c4e81fbb71f71c3f0dd6e664eaa454d246a39 Mon Sep 17 00:00:00 2001 From: Casper Welzel Andersen Date: Mon, 11 Nov 2019 16:53:03 +0100 Subject: [PATCH 4/4] Remove slippery "json-compatible" --- aiida/orm/querybuilder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida/orm/querybuilder.py b/aiida/orm/querybuilder.py index c33a805c0e..b0cbdac4cc 100644 --- a/aiida/orm/querybuilder.py +++ b/aiida/orm/querybuilder.py @@ -1752,7 +1752,7 @@ def queryhelp(self): # Note that such a comparison can only be True if the order of results is enforced qb.all() == qb2.all() - :return: a json-compatible queryhelp dictionary + :return: a queryhelp dictionary """ return copy.deepcopy({ 'path': self._path,