diff --git a/aiida/manage/manager.py b/aiida/manage/manager.py index 8914555c15..ed79afd026 100644 --- a/aiida/manage/manager.py +++ b/aiida/manage/manager.py @@ -182,17 +182,8 @@ def create_communicator(self, task_prefetch_count=None, with_orm=True): if task_prefetch_count is None: task_prefetch_count = self.get_config().get_option('daemon.worker_process_slots', profile.name) - url = profile.get_rmq_url() prefix = profile.rmq_prefix - # This needs to be here, because the verdi commands will call this function and when called in unit tests the - # testing_mode cannot be set. - testing_mode = profile.is_test_profile - - message_exchange = rmq.get_message_exchange_name(prefix) - task_exchange = rmq.get_task_exchange_name(prefix) - task_queue = rmq.get_launch_queue_name(prefix) - if with_orm: from aiida.orm.utils import serialize encoder = functools.partial(serialize.serialize, encoding='utf-8') @@ -204,14 +195,16 @@ def create_communicator(self, task_prefetch_count=None, with_orm=True): decoder = json.loads return kiwipy.rmq.RmqThreadCommunicator.connect( - connection_params={'url': url}, - message_exchange=message_exchange, + connection_params={'url': profile.get_rmq_url()}, + message_exchange=rmq.get_message_exchange_name(prefix), encoder=encoder, decoder=decoder, - task_exchange=task_exchange, - task_queue=task_queue, + task_exchange=rmq.get_task_exchange_name(prefix), + task_queue=rmq.get_launch_queue_name(prefix), task_prefetch_count=task_prefetch_count, - testing_mode=testing_mode, + # This is needed because the verdi commands will call this function and when called in unit tests the + # testing_mode cannot be set. + testing_mode=profile.is_test_profile, ) def get_daemon_client(self): diff --git a/aiida/restapi/resources.py b/aiida/restapi/resources.py index 0c6f1e9dee..4391970578 100644 --- a/aiida/restapi/resources.py +++ b/aiida/restapi/resources.py @@ -409,10 +409,9 @@ def get(self, id=None, page=None): # pylint: disable=redefined-builtin :return: http response """ - ## Decode url parts + headers = self.utils.build_headers(url=request.url, total_count=1) + path = unquote(request.path) - url = unquote(request.url) - url_root = unquote(request.url_root) ## Parse request (resource_type, page, node_id, query_type) = self.utils.parse_path(path, parse_pk_uuid=self.parse_pk_uuid) @@ -428,14 +427,11 @@ def get(self, id=None, page=None): # pylint: disable=redefined-builtin projectable_properties, ordering = self.trans.get_projectable_properties() results = dict(fields=projectable_properties, ordering=ordering) - ## Build response and return it - headers = self.utils.build_headers(url=request.url, total_count=1) - ## Build response data = dict( method=request.method, - url=url, - url_root=url_root, + url=unquote(request.url), + url_root=unquote(request.url_root), path=path, id=node_id, query_string=request.query_string.decode('utf-8'), diff --git a/aiida/restapi/translator/nodes/node.py b/aiida/restapi/translator/nodes/node.py index 1cb86b402e..6c68ee3a6e 100644 --- a/aiida/restapi/translator/nodes/node.py +++ b/aiida/restapi/translator/nodes/node.py @@ -8,10 +8,22 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Translator for node""" +import pkgutil +import imp +import inspect +import os + from aiida import orm -from aiida.common.exceptions import InputValidationError, ValidationError, InvalidOperation +from aiida.orm import Node, Data +from aiida.common.exceptions import ( + InputValidationError, ValidationError, InvalidOperation, LoadingEntryPointError, EntryPointError +) from aiida.manage.manager import get_manager +from aiida.plugins.entry_point import load_entry_point, get_entry_point_names from aiida.restapi.translator.base import BaseTranslator +from aiida.restapi.common.identifiers import get_full_type_filters +from aiida.restapi.common.exceptions import RestFeatureNotAvailable, RestInputValidationError, RestValidationError +from aiida.restapi.common.identifiers import get_node_namespace, load_entry_point_from_full_type, construct_full_type class NodeTranslator(BaseTranslator): @@ -197,7 +209,6 @@ def set_query( if full_type: # If full_type is not none, convert it into node_type # and process_type filters to pass it to query help - from aiida.restapi.common.identifiers import get_full_type_filters full_type_filter = get_full_type_filters(full_type) filters.update(full_type_filter) @@ -301,11 +312,6 @@ def _get_subclasses(self, parent=None, parent_class=None, recursive=True): :param recursive: True/False (go recursively into submodules) """ - import pkgutil - import imp - import inspect - import os - # If no parent class is specified set it to self.__class parent = self.__class__ if parent is None else parent @@ -331,7 +337,7 @@ def _get_subclasses(self, parent=None, parent_class=None, recursive=True): if parent_class is None: raise TypeError('argument parent_class cannot be None') - # Recursively check the subpackages + # Recursively check the subpackages results = {} for _, name, is_pkg in pkgutil.walk_packages([package_path]): @@ -355,6 +361,7 @@ def _get_subclasses(self, parent=None, parent_class=None, recursive=True): # Look in submodules elif is_pkg and recursive: results.update(self._get_subclasses(parent=app_module, parent_class=parent_class)) + return results def get_derived_properties(self, node): @@ -389,11 +396,6 @@ def get_all_download_formats(full_type=None): """ returns dict of possible node formats for all available node types """ - from aiida.plugins.entry_point import load_entry_point, get_entry_point_names - from aiida.restapi.common.identifiers import load_entry_point_from_full_type, construct_full_type - from aiida.common import EntryPointError - from aiida.common.exceptions import LoadingEntryPointError - from aiida.restapi.common.exceptions import RestFeatureNotAvailable, RestInputValidationError all_formats = {} @@ -442,14 +444,12 @@ def get_downloadable_data(node, download_format=None): invoke the get_downloadable_data method in the Data transaltor. Otherwise it raises RestFeatureNotAvailable exception """ - from aiida.orm import Data - from aiida.restapi.translator.nodes.data import DataTranslator # pylint: disable=cyclic-import - from aiida.restapi.common.exceptions import RestFeatureNotAvailable # This needs to be here because currently, for all nodes the `NodeTranslator` will be instantiated. Once that # logic is cleaned where the correct translator sub class is instantiated based on the node type that is # referenced, this hack can be removed. if isinstance(node, Data): + from .data import DataTranslator # pylint: disable=cyclic-import downloadable_data = DataTranslator.get_downloadable_data(node, download_format=download_format) return downloadable_data @@ -464,8 +464,6 @@ def get_repo_list(node, filename=''): :param filename: folder name (optional) :return: folder list """ - from aiida.restapi.common.exceptions import RestInputValidationError - try: flist = node.list_objects(filename) except IOError: @@ -484,7 +482,6 @@ def get_repo_contents(node, filename=''): :param filename: folder or file name (optional) :return: file content in bytes to download """ - from aiida.restapi.common.exceptions import RestInputValidationError, RestValidationError if filename: try: @@ -523,7 +520,6 @@ def get_file_content(node, file_name): :param file_name: name of the file to return its contents :return: """ - import os file_parts = file_name.split(os.sep) if len(file_parts) > 1: @@ -565,8 +561,6 @@ def get_formatted_result(self, label): else: result_name = self.__label__ - from aiida.restapi.common.identifiers import construct_full_type - for node_entry in results[result_name]: # construct full_type and add it to every node try: @@ -588,8 +582,6 @@ def get_namespace(): return full_types of the nodes """ - from aiida.restapi.common.identifiers import get_node_namespace - return get_node_namespace().get_description() def get_io_tree(self, uuid_pattern, tree_in_limit, tree_out_limit): @@ -599,8 +591,6 @@ def get_io_tree(self, uuid_pattern, tree_in_limit, tree_out_limit): :param uuid_pattern: main node uuid :return: json data to display node tree """ - from aiida.orm.querybuilder import QueryBuilder - from aiida.orm import Node def get_node_description(node): """ @@ -619,7 +609,7 @@ def get_node_description(node): # Check whether uuid_pattern identifies a unique node self._check_id_validity(uuid_pattern) - qb_obj = QueryBuilder() + qb_obj = orm.QueryBuilder() qb_obj.append(Node, tag='main', project=['*'], filters=self._id_filter) nodes = [] @@ -647,7 +637,7 @@ def get_node_description(node): }) # get all incoming - qb_obj = QueryBuilder() + qb_obj = orm.QueryBuilder() qb_obj.append(Node, tag='main', project=['*'], filters=self._id_filter) qb_obj.append(Node, tag='in', project=['*'], edge_project=['label', 'type'], with_outgoing='main').order_by({'in': [{ @@ -686,7 +676,7 @@ def get_node_description(node): }) # get all outgoing - qb_obj = QueryBuilder() + qb_obj = orm.QueryBuilder() qb_obj.append(Node, tag='main', project=['*'], filters=self._id_filter) qb_obj.append(Node, tag='out', project=['*'], edge_project=['label', 'type'], with_incoming='main').order_by({'out': [{ @@ -725,12 +715,12 @@ def get_node_description(node): }) # count total no of nodes - builder = QueryBuilder() + builder = orm.QueryBuilder() builder.append(Node, tag='main', project=['id'], filters=self._id_filter) builder.append(Node, tag='in', project=['id'], with_outgoing='main') total_no_of_incomings = builder.count() - builder = QueryBuilder() + builder = orm.QueryBuilder() builder.append(Node, tag='main', project=['id'], filters=self._id_filter) builder.append(Node, tag='out', project=['id'], with_incoming='main') total_no_of_outgoings = builder.count() diff --git a/aiida/tools/data/array/kpoints/seekpath.py b/aiida/tools/data/array/kpoints/seekpath.py index 9aa9dc36bb..0d4c59b6a0 100644 --- a/aiida/tools/data/array/kpoints/seekpath.py +++ b/aiida/tools/data/array/kpoints/seekpath.py @@ -138,22 +138,19 @@ def get_kpoints_path(structure, parameters): result = {} rawdict = seekpath.get_path(structure=structure_tuple, **parameters) + result['parameters'] = Dict(dict=rawdict) + # Replace conv structure with AiiDA StructureData conv_lattice = rawdict.pop('conv_lattice') conv_positions = rawdict.pop('conv_positions') conv_types = rawdict.pop('conv_types') - conv_tuple = (conv_lattice, conv_positions, conv_types) - conv_structure = spglib_tuple_to_structure(conv_tuple, kind_info, kinds) + result['conv_structure'] = spglib_tuple_to_structure((conv_lattice, conv_positions, conv_types), kind_info, kinds) # Replace primitive structure with AiiDA StructureData primitive_lattice = rawdict.pop('primitive_lattice') primitive_positions = rawdict.pop('primitive_positions') primitive_types = rawdict.pop('primitive_types') - primitive_tuple = (primitive_lattice, primitive_positions, primitive_types) - primitive_structure = spglib_tuple_to_structure(primitive_tuple, kind_info, kinds) - - result['parameters'] = Dict(dict=rawdict) - result['primitive_structure'] = primitive_structure - result['conv_structure'] = conv_structure + result['primitive_structure'] = spglib_tuple_to_structure((primitive_lattice, primitive_positions, primitive_types), + kind_info, kinds) return result diff --git a/aiida/tools/dbimporters/plugins/mpds.py b/aiida/tools/dbimporters/plugins/mpds.py index 6b4d733177..1a11b9aad7 100644 --- a/aiida/tools/dbimporters/plugins/mpds.py +++ b/aiida/tools/dbimporters/plugins/mpds.py @@ -187,9 +187,8 @@ def find(self, query, fmt=DEFAULT_API_FORMAT): content = self.get_response_content(response, fmt=ApiFormat.JSON) count = content['count'] - npages = content['npages'] - for page in range(npages): + for page in range(content['npages']): response = self.get(q=json.dumps(query), fmt=fmt, pagesize=pagesize, page=page) content = self.get_response_content(response, fmt=fmt) @@ -209,9 +208,8 @@ def find(self, query, fmt=DEFAULT_API_FORMAT): elif fmt == ApiFormat.CIF: - lines = content.splitlines() cif = [] - for line in lines: + for line in content.splitlines(): if cif: if line.startswith('data_'): text = '\n'.join(cif) @@ -219,9 +217,8 @@ def find(self, query, fmt=DEFAULT_API_FORMAT): yield text else: cif.append(line) - else: - if line.startswith('data_'): - cif.append(line) + elif line.startswith('data_'): + cif.append(line) if cif: yield '\n'.join(cif) diff --git a/aiida/tools/importexport/dbexport/__init__.py b/aiida/tools/importexport/dbexport/__init__.py index 60984ce4bb..8c5b3d98ff 100644 --- a/aiida/tools/importexport/dbexport/__init__.py +++ b/aiida/tools/importexport/dbexport/__init__.py @@ -610,6 +610,7 @@ def _collect_archive_data( :raises `~aiida.common.exceptions.LicensingException`: if any node is licensed under forbidden license. """ + # pylint: disable=too-many-locals EXPORT_LOGGER.debug('STARTING EXPORT...') # Backwards-compatibility @@ -866,6 +867,7 @@ def _collect_entity_queries( include_logs: bool = True, ) -> Dict[str, orm.QueryBuilder]: """Gather partial queries for all entities to export.""" + # pylint: disable=too-many-locals # Progress bar initialization - Entities progress_bar = get_progress_bar(total=1, disable=silent) progress_bar.set_description_str('Initializing export of all entities', refresh=True) diff --git a/pyproject.toml b/pyproject.toml index 6c76ce747f..3a46a24cb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,14 +19,11 @@ disable = [ "inconsistent-return-statements", "locally-disabled", "logging-fstring-interpolation", - "missing-class-docstring", - "missing-function-docstring", "no-else-raise", "too-few-public-methods", "too-many-ancestors", "too-many-arguments", "too-many-instance-attributes", - "too-many-locals", "useless-suppression", ] @@ -44,6 +41,11 @@ good-names = [ "ArithmeticAddCalculation", "MultiplyAddWorkChain" ] +no-docstring-rgx = "^_,setUp,tearDown" +docstring-min-length = 5 + +[tool.pylint.design] +max-locals = 20 [tool.pytest.ini_options] minversion = "6.0" diff --git a/tests/backends/aiida_sqlalchemy/test_query.py b/tests/backends/aiida_sqlalchemy/test_query.py index a609cddf79..b918603ca9 100644 --- a/tests/backends/aiida_sqlalchemy/test_query.py +++ b/tests/backends/aiida_sqlalchemy/test_query.py @@ -10,6 +10,7 @@ """Tests for generic queries.""" from aiida.backends.testbase import AiidaTestCase +from aiida.orm import Group, User, Computer, Node, Data, ProcessNode, QueryBuilder class TestQueryBuilderSQLA(AiidaTestCase): @@ -17,15 +18,11 @@ class TestQueryBuilderSQLA(AiidaTestCase): def test_clsf_sqla(self): """Test SQLA classifiers""" - from aiida.orm import Group, User, Computer, Node, Data - from aiida.orm import ProcessNode from aiida.backends.sqlalchemy.models.node import DbNode from aiida.backends.sqlalchemy.models.group import DbGroup from aiida.backends.sqlalchemy.models.user import DbUser from aiida.backends.sqlalchemy.models.computer import DbComputer - from aiida.orm.querybuilder import QueryBuilder - q_b = QueryBuilder() for aiida_cls, orm_cls in zip((Group, User, Computer, Node, Data, ProcessNode), (DbGroup, DbUser, DbComputer, DbNode, DbNode, DbNode)): @@ -39,8 +36,6 @@ class QueryBuilderLimitOffsetsTestSQLA(AiidaTestCase): def test_ordering_limits_offsets_sqla(self): """Test ordering limits offsets of SQLA query results.""" - from aiida.orm import Node, Data - from aiida.orm.querybuilder import QueryBuilder # Creating 10 nodes with an attribute that can be ordered for i in range(10): node = Data() diff --git a/tests/sphinxext/conftest.py b/tests/sphinxext/conftest.py index feb7dbe8eb..9c9362421d 100644 --- a/tests/sphinxext/conftest.py +++ b/tests/sphinxext/conftest.py @@ -33,12 +33,16 @@ def inner(name): class SphinxBuild: + """Class for testing sphinx builds""" def __init__(self, app: SphinxTestApp, src: Path): self.app = app self.src = src def build(self, assert_pass=True): + """Build sphinx app. + + :param assert_pass: if True, assert that no warnings are raised during build""" try: sys.path.append(os.path.abspath(WORKCHAIN_DIR)) self.app.build() @@ -63,6 +67,15 @@ def outdir(self): @pytest.fixture def sphinx_build_factory(make_app, tmp_path): + """SphinxBuild factory fixture + + Usage:: + + def test_wc(sphinx_build_factory): + ... + sphinx_build = sphinx_build_factory('workchain', buildername='xml') + sphinx_build.build(assert_pass=True) + """ def _func(src_folder, **kwargs): shutil.copytree(SRC_DIR / src_folder, tmp_path / src_folder)