diff --git a/aiida/cmdline/utils/echo.py b/aiida/cmdline/utils/echo.py index be0227400d..133ace8668 100644 --- a/aiida/cmdline/utils/echo.py +++ b/aiida/cmdline/utils/echo.py @@ -10,6 +10,7 @@ """Convenience functions for logging output from ``verdi`` commands.""" import collections import enum +import json import sys import click @@ -207,7 +208,6 @@ def echo_formatted_list(collection, attributes, sort=None, highlight=None, hide= def _format_dictionary_json_date(dictionary, sort_keys=True): """Return a dictionary formatted as a string using the json format and converting dates to strings.""" - from aiida.common import json def default_jsondump(data): """Function needed to decode datetimes, that would otherwise not be JSON-decodable.""" diff --git a/aiida/common/json.py b/aiida/common/json.py index c58ff58669..7151ded476 100644 --- a/aiida/common/json.py +++ b/aiida/common/json.py @@ -7,65 +7,73 @@ # For further information on the license, see the LICENSE.txt file # # For further information please visit http://www.aiida.net # ########################################################################### -""" -Abstracts JSON usage to ensure compatibility with Python2 and Python3. +"""Abstracts JSON usage to ensure compatibility with Python2 and Python3. Use this module prefentially over standard json to ensure compatibility. +.. deprecated:: This module is deprecated in v2.0.0 and should no longer be used. Python 2 support has long since been + dropped and for Python 3, one should simply use the ``json`` module of the standard library directly. + """ -import simplejson +import codecs +import json +import warnings -JSONEncoder = simplejson.JSONEncoder +from aiida.common.warnings import AiidaDeprecationWarning +warnings.warn( + 'This module has been deprecated and should no longer be used. Use the `json` standard library instead.', + AiidaDeprecationWarning +) -def dump(data, fhandle, **kwargs): - """ - Write JSON encoded 'data' to a file-like object, fhandle - Use open(filename, 'wb') to write. - The utf8write object is used to ensure that the resulting serialised data is - encoding as UTF8. - Any strings with non-ASCII characters need to be unicode strings. - We use ensure_ascii=False to write unicode characters specifically - as this improves the readability of the json and reduces the file size. - """ - import codecs - utf8writer = codecs.getwriter('utf8') - simplejson.dump(data, utf8writer(fhandle), ensure_ascii=False, encoding='utf8', **kwargs) +def dump(data, handle, **kwargs): + """Serialize ``data`` as a JSON formatted stream to ``handle``. -def dumps(data, **kwargs): - """ - Write JSON encoded 'data' to a string. - simplejson is useful here as it always returns unicode if ensure_ascii=False is used, - unlike the standard library json, rather than being dependant on the input. - We use also ensure_ascii=False to write unicode characters specifically - as this improves the readability of the json and reduces the file size. - When writing to file, use open(filename, 'w', encoding='utf8') + We use ``ensure_ascii=False`` to write unicode characters specifically as this improves the readability of the json + and reduces the file size. """ - return simplejson.dumps(data, ensure_ascii=False, encoding='utf8', **kwargs) + try: + if 'b' in handle.mode: + handle = codecs.getwriter('utf-8')(handle) + except AttributeError: + pass + return json.dump(data, handle, ensure_ascii=False, **kwargs) -def load(fhandle, **kwargs): + +def dumps(data, **kwargs): + """Serialize ``data`` as a JSON formatted string. + + We use ``ensure_ascii=False`` to write unicode characters specifically as this improves the readability of the json + and reduces the file size. """ - Deserialise a JSON file. + return json.dumps(data, ensure_ascii=False, **kwargs) + - For encoding consistency, open(filename, 'r', encoding='utf8') should be used. +def load(handle, **kwargs): + """Deserialize ``handle`` text or binary file containing a JSON document to a Python object. - :raises ValueError: if no valid JSON object could be decoded + :raises ValueError: if no valid JSON object could be decoded. """ + if 'b' in handle.mode: + handle = codecs.getreader('utf-8')(handle) + try: - return simplejson.load(fhandle, encoding='utf8', **kwargs) - except simplejson.errors.JSONDecodeError: - raise ValueError + return json.load(handle, **kwargs) + except json.JSONDecodeError as exc: + raise ValueError from exc -def loads(json_string, **kwargs): - """ - Deserialise a JSON string. +def loads(string, **kwargs): + """Deserialize text or binary ``string`` containing a JSON document to a Python object. - :raises ValueError: if no valid JSON object could be decoded + :raises ValueError: if no valid JSON object could be decoded. """ + if isinstance(string, bytes): + string = string.decode('utf-8') + try: - return simplejson.loads(json_string, encoding='utf8', **kwargs) - except simplejson.errors.JSONDecodeError: - raise ValueError + return json.loads(string, **kwargs) + except json.JSONDecodeError as exc: + raise ValueError from exc diff --git a/aiida/engine/processes/calcjobs/calcjob.py b/aiida/engine/processes/calcjobs/calcjob.py index 86c31ae3b8..92384572a3 100644 --- a/aiida/engine/processes/calcjobs/calcjob.py +++ b/aiida/engine/processes/calcjobs/calcjob.py @@ -9,6 +9,7 @@ ########################################################################### """Implementation of the CalcJob process.""" import io +import json import os import shutil from typing import Any, Dict, Hashable, Optional, Type, Union @@ -582,7 +583,6 @@ def presubmit(self, folder: Folder) -> CalcInfo: """ # pylint: disable=too-many-locals,too-many-statements,too-many-branches - from aiida.common import json from aiida.common.datastructures import CodeInfo, CodeRunMode from aiida.common.exceptions import InputValidationError, InvalidOperation, PluginInternalError, ValidationError from aiida.common.utils import validate_list_of_string_tuples diff --git a/aiida/manage/configuration/config.py b/aiida/manage/configuration/config.py index 85b7123cfe..4b444ac288 100644 --- a/aiida/manage/configuration/config.py +++ b/aiida/manage/configuration/config.py @@ -8,8 +8,10 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Module that defines the configuration file of an AiiDA instance and functions to create and load it.""" +import codecs from functools import lru_cache from importlib import resources +import json import os import shutil import tempfile @@ -17,7 +19,6 @@ import jsonschema -from aiida.common import json from aiida.common.exceptions import ConfigurationError from . import schema as schema_module @@ -81,7 +82,7 @@ def from_file(cls, filepath): from .migrations import check_and_migrate_config, config_needs_migrating try: - with open(filepath, 'r', encoding='utf8') as handle: + with open(filepath, 'rb') as handle: config = json.load(handle) except FileNotFoundError: config = Config(filepath, check_and_migrate_config({})) @@ -492,7 +493,7 @@ def store(self): # Otherwise, we write the content to a temporary file and compare its md5 checksum with the current config on # disk. When the checksums differ, we first create a backup and only then overwrite the existing file. with tempfile.NamedTemporaryFile() as handle: - json.dump(self.dictionary, handle, indent=DEFAULT_CONFIG_INDENT_SIZE) + json.dump(self.dictionary, codecs.getwriter('utf-8')(handle), indent=DEFAULT_CONFIG_INDENT_SIZE) handle.seek(0) if md5_from_filelike(handle) != md5_file(self.filepath): @@ -522,7 +523,7 @@ def _atomic_write(self, filepath=None): # Create a temporary file in the same directory as the target filepath, which guarantees that the temporary # file is on the same filesystem, which is necessary to be able to use ``os.rename``. Since we are moving the # temporary file, we should also tell the tempfile to not be automatically deleted as that will raise. - with tempfile.NamedTemporaryFile(dir=os.path.dirname(filepath), delete=False) as handle: + with tempfile.NamedTemporaryFile(dir=os.path.dirname(filepath), delete=False, mode='w') as handle: try: json.dump(self.dictionary, handle, indent=DEFAULT_CONFIG_INDENT_SIZE) finally: diff --git a/aiida/orm/implementation/utils.py b/aiida/orm/implementation/utils.py index 54a6a4bb62..76791336c2 100644 --- a/aiida/orm/implementation/utils.py +++ b/aiida/orm/implementation/utils.py @@ -63,7 +63,7 @@ def clean_builtin(val): It mainly checks that we don't store NaN or Inf. """ # This is a whitelist of all the things we understand currently - if val is None or isinstance(val, (bool, str, Decimal)): + if val is None or isinstance(val, (bool, str)): return val # This fixes #2773 - in python3, ``numpy.int64(-1)`` cannot be json-serialized @@ -77,7 +77,7 @@ def clean_builtin(val): # This is for float-like types, like ``numpy.float128`` that are not json-serializable # Note that `numbers.Real` also match booleans but they are already returned above - if isinstance(val, numbers.Real): + if isinstance(val, (numbers.Real, Decimal)): string_representation = f'{{:.{AIIDA_FLOAT_PRECISION}g}}'.format(val) new_val = float(string_representation) if 'e' in string_representation and new_val.is_integer(): diff --git a/aiida/orm/nodes/data/array/bands.py b/aiida/orm/nodes/data/array/bands.py index dfb8d4b22f..c47f96afb8 100644 --- a/aiida/orm/nodes/data/array/bands.py +++ b/aiida/orm/nodes/data/array/bands.py @@ -12,6 +12,7 @@ This module defines the classes related to band structures or dispersions in a Brillouin zone, and how to operate on them. """ +import json from string import Template import numpy @@ -811,8 +812,6 @@ def _prepare_mpl_singlefile(self, *args, **kwargs): For the possible parameters, see documentation of :py:meth:`~aiida.orm.nodes.data.array.bands.BandsData._matplotlib_get_dict` """ - from aiida.common import json - all_data = self._matplotlib_get_dict(*args, **kwargs) s_header = MATPLOTLIB_HEADER_TEMPLATE.substitute() @@ -834,8 +833,6 @@ def _prepare_mpl_withjson(self, main_file_name='', *args, **kwargs): # pylint: """ import os - from aiida.common import json - all_data = self._matplotlib_get_dict(*args, main_file_name=main_file_name, **kwargs) json_fname = os.path.splitext(main_file_name)[0] + '_data.json' @@ -866,8 +863,6 @@ def _prepare_mpl_pdf(self, main_file_name='', *args, **kwargs): # pylint: disab import sys import tempfile - from aiida.common import json - all_data = self._matplotlib_get_dict(*args, **kwargs) # Use the Agg backend @@ -911,7 +906,6 @@ def _prepare_mpl_png(self, main_file_name='', *args, **kwargs): # pylint: disab For the possible parameters, see documentation of :py:meth:`~aiida.orm.nodes.data.array.bands.BandsData._matplotlib_get_dict` """ - import json import os import subprocess import sys @@ -1237,7 +1231,6 @@ def _prepare_json(self, main_file_name='', comments=True): # pylint: disable=un format) """ from aiida import get_file_header - from aiida.common import json json_dict = self._get_band_segments(cartesian=True) json_dict['original_uuid'] = self.uuid diff --git a/aiida/orm/nodes/data/structure.py b/aiida/orm/nodes/data/structure.py index b65b736ced..700cb5f4f6 100644 --- a/aiida/orm/nodes/data/structure.py +++ b/aiida/orm/nodes/data/structure.py @@ -15,6 +15,7 @@ import copy import functools import itertools +import json from aiida.common.constants import elements from aiida.common.exceptions import UnsupportedSpeciesError @@ -1016,8 +1017,6 @@ def _prepare_chemdoodle(self, main_file_name=''): # pylint: disable=unused-argu import numpy as np - from aiida.common import json - supercell_factors = [1, 1, 1] # Get cell vectors and atomic position diff --git a/aiida/restapi/translator/nodes/data/array/bands.py b/aiida/restapi/translator/nodes/data/array/bands.py index 5b023c4026..87f1d6542d 100644 --- a/aiida/restapi/translator/nodes/data/array/bands.py +++ b/aiida/restapi/translator/nodes/data/array/bands.py @@ -10,6 +10,7 @@ """ Translator for bands data """ +import json from aiida.restapi.translator.nodes.data import DataTranslator @@ -44,7 +45,6 @@ def get_derived_properties(node): """ response = {} - from aiida.common import json json_string = node._exportcontent('json', comments=False) # pylint: disable=protected-access json_content = json.loads(json_string[0]) response['bands'] = json_content diff --git a/aiida/schedulers/datastructures.py b/aiida/schedulers/datastructures.py index 2ca464f925..b788724ed4 100644 --- a/aiida/schedulers/datastructures.py +++ b/aiida/schedulers/datastructures.py @@ -16,6 +16,7 @@ """ import abc import enum +import json from aiida.common import AIIDA_LOGGER from aiida.common.extendeddicts import AttributeDict, DefaultFieldsAttributeDict @@ -543,8 +544,6 @@ def serialize(self): :return: A string with serialised representation of the current data. """ - from aiida.common import json - return json.dumps(self.get_dict()) def get_dict(self): @@ -574,6 +573,4 @@ def load_from_serialized(cls, data): :param data: The string with the JSON-serialised data to load from """ - from aiida.common import json - return cls.load_from_dict(json.loads(data)) diff --git a/aiida/storage/psql_dos/migrations/utils/create_dbattribute.py b/aiida/storage/psql_dos/migrations/utils/create_dbattribute.py index 54ce1dac8b..0682d016f4 100644 --- a/aiida/storage/psql_dos/migrations/utils/create_dbattribute.py +++ b/aiida/storage/psql_dos/migrations/utils/create_dbattribute.py @@ -14,8 +14,8 @@ from __future__ import annotations import datetime +import json -from aiida.common import json from aiida.common.exceptions import ValidationError from aiida.common.timezone import get_current_timezone, is_naive, make_aware diff --git a/aiida/storage/psql_dos/migrations/utils/legacy_workflows.py b/aiida/storage/psql_dos/migrations/utils/legacy_workflows.py index 92bcb4f95e..53dd8cdd6d 100644 --- a/aiida/storage/psql_dos/migrations/utils/legacy_workflows.py +++ b/aiida/storage/psql_dos/migrations/utils/legacy_workflows.py @@ -9,13 +9,14 @@ ########################################################################### # pylint: disable=invalid-name """Utilities for removing legacy workflows.""" +import codecs +import json import sys import click from sqlalchemy.sql import func, select, table from aiida.cmdline.utils import echo -from aiida.common import json def json_serializer(obj): @@ -70,7 +71,7 @@ def export_workflow_data(connection, profile): prefix='legacy-workflows', suffix='.json', dir='.', delete=delete_on_close, mode='wb' ) as handle: filename = handle.name - json.dump(data, handle, default=json_serializer) + json.dump(data, codecs.getwriter('utf-8')(handle), default=json_serializer) # If delete_on_close is False, we are running for the user and add additional message of file location if not delete_on_close: diff --git a/aiida/storage/psql_dos/migrations/utils/utils.py b/aiida/storage/psql_dos/migrations/utils/utils.py index 89d2fc5cb9..7ce3cf3fe1 100644 --- a/aiida/storage/psql_dos/migrations/utils/utils.py +++ b/aiida/storage/psql_dos/migrations/utils/utils.py @@ -12,6 +12,7 @@ import datetime import functools import io +import json import os import pathlib import re @@ -21,7 +22,7 @@ from disk_objectstore.utils import LazyOpener import numpy -from aiida.common import exceptions, json +from aiida.common import exceptions from aiida.repository.backend import AbstractRepositoryBackend from aiida.repository.common import File, FileType from aiida.repository.repository import Repository diff --git a/aiida/storage/psql_dos/utils.py b/aiida/storage/psql_dos/utils.py index 7de46c4539..4d6be94335 100644 --- a/aiida/storage/psql_dos/utils.py +++ b/aiida/storage/psql_dos/utils.py @@ -9,6 +9,7 @@ ########################################################################### # pylint: disable=import-error,no-name-in-module """Utility functions specific to the SqlAlchemy backend.""" +import json from typing import TypedDict @@ -33,8 +34,6 @@ def create_sqlalchemy_engine(config: PsqlConfig): """ from sqlalchemy import create_engine - from aiida.common import json - # The hostname may be `None`, which is a valid value in the case of peer authentication for example. In this case # it should be converted to an empty string, because otherwise the `None` will be converted to string literal "None" hostname = config['database_hostname'] or '' diff --git a/aiida/storage/sqlite_zip/migrator.py b/aiida/storage/sqlite_zip/migrator.py index 52cd81a91a..281fe8e099 100644 --- a/aiida/storage/sqlite_zip/migrator.py +++ b/aiida/storage/sqlite_zip/migrator.py @@ -10,6 +10,7 @@ """Versioning and migration implementation for the sqlite_zip format.""" import contextlib from datetime import datetime +import json import os from pathlib import Path import shutil @@ -25,7 +26,6 @@ from alembic.script import ScriptDirectory from archive_path import ZipPath, extract_file_in_zip, open_file_in_tar, open_file_in_zip -from aiida.common import json from aiida.common.exceptions import CorruptStorage, IncompatibleStorageSchema, StorageMigrationError from aiida.common.progress_reporter import get_progress_reporter from aiida.storage.log import MIGRATE_LOGGER diff --git a/aiida/storage/sqlite_zip/utils.py b/aiida/storage/sqlite_zip/utils.py index cd2838314e..18ed4996cb 100644 --- a/aiida/storage/sqlite_zip/utils.py +++ b/aiida/storage/sqlite_zip/utils.py @@ -8,6 +8,7 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Utilities for this backend.""" +import json from pathlib import Path import tarfile from typing import Any, Dict, Optional, Union @@ -17,7 +18,6 @@ from sqlalchemy import event from sqlalchemy.future.engine import Engine, create_engine -from aiida.common import json from aiida.common.exceptions import CorruptStorage, UnreachableStorage META_FILENAME = 'metadata.json' diff --git a/aiida/tools/dbimporters/plugins/mpds.py b/aiida/tools/dbimporters/plugins/mpds.py index 3c12892105..52fd7b9439 100644 --- a/aiida/tools/dbimporters/plugins/mpds.py +++ b/aiida/tools/dbimporters/plugins/mpds.py @@ -10,11 +10,11 @@ """"Implementation of `DbImporter` for the MPDS database.""" import copy import enum +import json import os import requests -from aiida.common import json from aiida.tools.dbimporters.baseclasses import CifEntry, DbEntry, DbImporter, DbSearchResults diff --git a/aiida/tools/ipython/ipython_magics.py b/aiida/tools/ipython/ipython_magics.py index 494549416a..4e7110fd06 100644 --- a/aiida/tools/ipython/ipython_magics.py +++ b/aiida/tools/ipython/ipython_magics.py @@ -33,6 +33,7 @@ In [2]: %aiida """ +import json from IPython import get_ipython, version_info from IPython.core import magic @@ -97,8 +98,6 @@ def _repr_json_(self): """ Output in JSON format. """ - from aiida.common import json - obj = {'current_state': self.current_state} if version_info[0] >= 3: return obj diff --git a/environment.yml b/environment.yml index 37fcb122e3..6c4143e1d4 100644 --- a/environment.yml +++ b/environment.yml @@ -30,7 +30,6 @@ dependencies: - python-dateutil~=2.8 - pytz~=2021.1 - pyyaml~=5.4 -- simplejson~=3.16 - sqlalchemy~=1.4.22 - tabulate~=0.8.5 - tqdm~=4.45 diff --git a/pyproject.toml b/pyproject.toml index e2185b306f..d9d5cf8060 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,6 @@ dependencies = [ "python-dateutil~=2.8", "pytz~=2021.1", "pyyaml~=5.4", - "simplejson~=3.16", "sqlalchemy~=1.4.22", "tabulate~=0.8.5", "tqdm~=4.45", diff --git a/requirements/requirements-py-3.10.txt b/requirements/requirements-py-3.10.txt index a044f49400..08d55f8435 100644 --- a/requirements/requirements-py-3.10.txt +++ b/requirements/requirements-py-3.10.txt @@ -133,7 +133,6 @@ seekpath==1.9.7 Send2Trash==1.8.0 setuptools-scm==6.3.2 shortuuid==1.0.8 -simplejson==3.17.6 six==1.16.0 snowballstemmer==2.2.0 soupsieve==2.3.1 diff --git a/requirements/requirements-py-3.8.txt b/requirements/requirements-py-3.8.txt index be81f85218..6c35d8780c 100644 --- a/requirements/requirements-py-3.8.txt +++ b/requirements/requirements-py-3.8.txt @@ -135,7 +135,6 @@ seekpath==1.9.7 Send2Trash==1.8.0 setuptools-scm==6.3.2 shortuuid==1.0.8 -simplejson==3.17.6 six==1.16.0 snowballstemmer==2.2.0 soupsieve==2.3.1 diff --git a/requirements/requirements-py-3.9.txt b/requirements/requirements-py-3.9.txt index 54b2c6afe0..ce0025c74b 100644 --- a/requirements/requirements-py-3.9.txt +++ b/requirements/requirements-py-3.9.txt @@ -134,7 +134,6 @@ seekpath==1.9.7 Send2Trash==1.8.0 setuptools-scm==6.3.2 shortuuid==1.0.8 -simplejson==3.17.6 six==1.16.0 snowballstemmer==2.2.0 soupsieve==2.3.1 diff --git a/tests/common/test_extendeddicts.py b/tests/common/test_extendeddicts.py index 881ccd7a1d..6830f68a1c 100644 --- a/tests/common/test_extendeddicts.py +++ b/tests/common/test_extendeddicts.py @@ -9,12 +9,12 @@ ########################################################################### """Tests for the extended dictionary classes.""" # pylint: disable=pointless-statement,attribute-defined-outside-init - import copy +import json import pickle import unittest -from aiida.common import exceptions, extendeddicts, json +from aiida.common import exceptions, extendeddicts class FFADExample(extendeddicts.FixedFieldsAttributeDict): diff --git a/tests/manage/configuration/migrations/test_migrations.py b/tests/manage/configuration/migrations/test_migrations.py index 68c2b06336..3771c6cf3c 100644 --- a/tests/manage/configuration/migrations/test_migrations.py +++ b/tests/manage/configuration/migrations/test_migrations.py @@ -10,12 +10,12 @@ # pylint: disable=redefined-outer-name """Tests for the configuration migration functionality.""" import copy +import json import pathlib import uuid import pytest -from aiida.common import json from aiida.common.exceptions import ConfigurationError from aiida.manage.configuration.migrations import check_and_migrate_config from aiida.manage.configuration.migrations.migrations import MIGRATIONS, Initial, downgrade_config, upgrade_config diff --git a/tests/manage/configuration/test_config.py b/tests/manage/configuration/test_config.py index 17e2069f6d..e807946c4a 100644 --- a/tests/manage/configuration/test_config.py +++ b/tests/manage/configuration/test_config.py @@ -8,12 +8,13 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Tests for the ``Config`` class.""" +import json import os import pathlib import pytest -from aiida.common import exceptions, json +from aiida.common import exceptions from aiida.manage.configuration import Config, Profile, settings from aiida.manage.configuration.migrations import CURRENT_CONFIG_VERSION, OLDEST_COMPATIBLE_CONFIG_VERSION from aiida.manage.configuration.options import get_option diff --git a/tests/orm/test_logs.py b/tests/orm/test_logs.py index 66f342ab61..1fee563ba8 100644 --- a/tests/orm/test_logs.py +++ b/tests/orm/test_logs.py @@ -9,6 +9,7 @@ ########################################################################### # pylint: disable=no-self-use """ORM Log tests""" +import json import logging import pytest @@ -279,8 +280,6 @@ def test_raise_wrong_metadata_type_error(self): Test a TypeError exception is thrown with string metadata. Also test that metadata is correctly created. """ - from aiida.common import json - # Create CalculationNode calc = orm.CalculationNode().store() diff --git a/tests/restapi/test_routes.py b/tests/restapi/test_routes.py index 2d8252622d..220a6a0372 100644 --- a/tests/restapi/test_routes.py +++ b/tests/restapi/test_routes.py @@ -11,12 +11,12 @@ """Unittests for REST API.""" from datetime import date import io +import json from flask_cors.core import ACL_ORIGIN import pytest from aiida import orm -from aiida.common import json from aiida.common.links import LinkType from aiida.manage import get_manager from aiida.restapi.run_api import configure_api diff --git a/tests/storage/psql_dos/migrations/django_branch/test_0033_replace_text_field_with_json_field.py b/tests/storage/psql_dos/migrations/django_branch/test_0033_replace_text_field_with_json_field.py index db3d4e80b1..27082a8c9e 100644 --- a/tests/storage/psql_dos/migrations/django_branch/test_0033_replace_text_field_with_json_field.py +++ b/tests/storage/psql_dos/migrations/django_branch/test_0033_replace_text_field_with_json_field.py @@ -8,7 +8,9 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Test migration adding the `repository_metadata` column to the `Node` model.""" -from aiida.common import json, timezone +import json + +from aiida.common import timezone from aiida.common.utils import get_new_uuid from aiida.storage.psql_dos.migrator import PsqlDostoreMigrator diff --git a/tests/tools/archive/test_simple.py b/tests/tools/archive/test_simple.py index 43a58a1e7c..bee2df8468 100644 --- a/tests/tools/archive/test_simple.py +++ b/tests/tools/archive/test_simple.py @@ -8,11 +8,12 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Simple tests for the export and import routines""" +import json + from archive_path import ZipPath import pytest from aiida import orm -from aiida.common import json from aiida.common.exceptions import IncompatibleStorageSchema, LicensingException from aiida.common.links import LinkType from aiida.tools.archive import create_archive, import_archive diff --git a/tests/utils/archives.py b/tests/utils/archives.py index 8bb130c212..36f4ae87a9 100644 --- a/tests/utils/archives.py +++ b/tests/utils/archives.py @@ -8,6 +8,7 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Test utility to import, inspect, or migrate AiiDA export archives.""" +import json import os import tarfile from typing import List @@ -15,7 +16,6 @@ from archive_path import read_file_in_tar, read_file_in_zip -from aiida.common import json from tests.static import STATIC_DIR