diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 254c8245..3f1686a2 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,9 +1,9 @@
repos:
- repo: https://github.com/pycqa/isort
- rev: 7.0.0
+ rev: 8.0.1
hooks:
- id: isort
- repo: https://github.com/python/black
- rev: 25.11.0
+ rev: 26.3.1
hooks:
- id: black
diff --git a/dev-requirements.txt b/dev-requirements.txt
index a30293e4..5555c510 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -1,5 +1,5 @@
coverage[toml]
-black == 24.4.2
+black == 26.3.1
pre-commit
pyperf
sphinx
diff --git a/pyproject.toml b/pyproject.toml
index 1da2ac6a..4ef78f51 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ classifiers = [
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Operating System :: OS Independent",
]
-requires-python = ">=3.10"
+requires-python = ">=3.10" # Remember to bump Black's target-version below when updating this.
dependencies = [
"SQLAlchemy >=2.0, <2.1",
"alembic >=1.7",
@@ -60,6 +60,7 @@ branch = true
ignore_errors = true
[tool.black]
+target-version = ["py310"]
line-length = 120
force-exclude = '\.git|version.py'
diff --git a/spinedb_api/__init__.py b/spinedb_api/__init__.py
index a272df0e..925567a2 100644
--- a/spinedb_api/__init__.py
+++ b/spinedb_api/__init__.py
@@ -10,7 +10,7 @@
# this program. If not, see .
######################################################################################################################
-""" A package to interact with Spine DBs. """
+"""A package to interact with Spine DBs."""
from .db_mapping import DatabaseMapping
from .exception import (
diff --git a/spinedb_api/alembic/versions/39e860a11b05_add_alternatives_and_scenarios.py b/spinedb_api/alembic/versions/39e860a11b05_add_alternatives_and_scenarios.py
index 2b0fc29c..13ed2fed 100644
--- a/spinedb_api/alembic/versions/39e860a11b05_add_alternatives_and_scenarios.py
+++ b/spinedb_api/alembic/versions/39e860a11b05_add_alternatives_and_scenarios.py
@@ -102,8 +102,7 @@ def alter_tables_after_update():
date = datetime.now(timezone.utc)
conn = op.get_bind()
conn.execute(
- text(
- """
+ text("""
UPDATE next_id
SET
user = :user,
@@ -111,8 +110,7 @@ def alter_tables_after_update():
alternative_id = 2,
scenario_id = 1,
scenario_alternative_id = 1
- """
- ),
+ """),
{
"user": user,
"date": date,
diff --git a/spinedb_api/alembic/versions/bba1e2ef5153_move_to_entity_based_design.py b/spinedb_api/alembic/versions/bba1e2ef5153_move_to_entity_based_design.py
index f460f1c4..a2ddfbe1 100644
--- a/spinedb_api/alembic/versions/bba1e2ef5153_move_to_entity_based_design.py
+++ b/spinedb_api/alembic/versions/bba1e2ef5153_move_to_entity_based_design.py
@@ -142,33 +142,19 @@ def insert_into_new_tables():
]
op.bulk_insert(meta.tables["entity_class"], entity_classes)
# Id mappings
- obj_cls_to_ent_cls = {
- r.object_class_id: r.entity_class_id
- for r in conn.execute(
- text(
- """
+ obj_cls_to_ent_cls = {r.object_class_id: r.entity_class_id for r in conn.execute(text("""
SELECT object_class.id AS object_class_id, entity_class.id AS entity_class_id
FROM object_class, entity_class
WHERE entity_class.type_id = 1
AND object_class.name = entity_class.name
- """
- )
- )
- }
- rel_cls_to_ent_cls = {
- r.relationship_class_id: r.entity_class_id
- for r in conn.execute(
- text(
- """
+ """))}
+ rel_cls_to_ent_cls = {r.relationship_class_id: r.entity_class_id for r in conn.execute(text("""
SELECT relationship_class.id AS relationship_class_id, entity_class.id AS entity_class_id
FROM relationship_class, entity_class
WHERE entity_class.type_id = 2
AND relationship_class.name = entity_class.name
GROUP BY relationship_class_id, entity_class_id
- """
- )
- )
- }
+ """))}
temp_relationship_classes = [
{"entity_class_id": r.id, "type_id": 2, "commit_id": r.commit_id}
for r in conn.execute(text("SELECT id, commit_id FROM entity_class WHERE type_id = 2"))
@@ -195,33 +181,19 @@ def insert_into_new_tables():
]
op.bulk_insert(meta.tables["entity"], entities)
# Id mappings
- obj_to_ent = {
- r.object_id: r.entity_id
- for r in conn.execute(
- text(
- """
+ obj_to_ent = {r.object_id: r.entity_id for r in conn.execute(text("""
SELECT object.id AS object_id, entity.id AS entity_id
FROM object, entity
WHERE entity.type_id = 1
AND object.name = entity.name
- """
- )
- )
- }
- rel_to_ent = {
- r.relationship_id: r.entity_id
- for r in conn.execute(
- text(
- """
+ """))}
+ rel_to_ent = {r.relationship_id: r.entity_id for r in conn.execute(text("""
SELECT relationship.id AS relationship_id, entity.id AS entity_id
FROM relationship, entity
WHERE entity.type_id = 2
AND relationship.name = entity.name
GROUP BY relationship_id, entity_id
- """
- )
- )
- }
+ """))}
temp_relationships = [
{"entity_id": r.id, "entity_class_id": r.class_id, "type_id": 2, "commit_id": r.commit_id}
for r in conn.execute(text("SELECT id, class_id, commit_id FROM entity WHERE type_id = 2"))
@@ -236,15 +208,11 @@ def insert_into_new_tables():
"member_class_id": obj_cls_to_ent_cls[r.object_class_id],
"commit_id": r.commit_id,
}
- for r in conn.execute(
- text(
- """
+ for r in conn.execute(text("""
SELECT r.id, r.class_id, r.dimension, o.class_id AS object_class_id, r.object_id, r.commit_id
FROM relationship AS r, object AS o
WHERE r.object_id = o.id
- """
- )
- )
+ """))
]
op.bulk_insert(meta.tables["relationship_entity"], relationship_entities)
# Return metadata and id mappings
@@ -309,12 +277,10 @@ def update_tables(meta, obj_cls_to_ent_cls, rel_cls_to_ent_cls, obj_to_ent, rel_
{"entity_class_id": entity_class_id, "object_class_id": object_class_id},
)
conn.execute(
- text(
- """
+ text("""
UPDATE parameter_definition SET entity_class_id = :entity_class_id
WHERE object_class_id = :object_class_id
- """
- ),
+ """),
{
"entity_class_id": entity_class_id,
"object_class_id": object_class_id,
@@ -322,12 +288,10 @@ def update_tables(meta, obj_cls_to_ent_cls, rel_cls_to_ent_cls, obj_to_ent, rel_
)
for relationship_class_id, entity_class_id in rel_cls_to_ent_cls.items():
conn.execute(
- text(
- """
+ text("""
UPDATE parameter_definition SET entity_class_id = :entity_class_id
WHERE relationship_class_id = :relationship_class_id
- """
- ),
+ """),
{
"entity_class_id": entity_class_id,
"relationship_class_id": relationship_class_id,
@@ -343,12 +307,10 @@ def update_tables(meta, obj_cls_to_ent_cls, rel_cls_to_ent_cls, obj_to_ent, rel_
)
entity_class_id = ent_to_ent_cls[entity_id]
conn.execute(
- text(
- """
+ text("""
UPDATE parameter_value SET entity_id = :entity_id, entity_class_id = :entity_class_id
WHERE object_id = :object_id
- """
- ),
+ """),
{
"entity_id": entity_id,
"entity_class_id": entity_class_id,
@@ -358,12 +320,10 @@ def update_tables(meta, obj_cls_to_ent_cls, rel_cls_to_ent_cls, obj_to_ent, rel_
for relationship_id, entity_id in rel_to_ent.items():
entity_class_id = ent_to_ent_cls[entity_id]
conn.execute(
- text(
- """
+ text("""
UPDATE parameter_value SET entity_id = :entity_id, entity_class_id = :entity_class_id
WHERE relationship_id = :relationship_id
- """
- ),
+ """),
{
"entity_id": entity_id,
"entity_class_id": entity_class_id,
@@ -383,8 +343,7 @@ def update_tables(meta, obj_cls_to_ent_cls, rel_cls_to_ent_cls, obj_to_ent, rel_
user = "alembic"
date = datetime.now(timezone.utc)
conn.execute(
- text(
- """
+ text("""
UPDATE next_id
SET
user = :user,
@@ -393,8 +352,7 @@ def update_tables(meta, obj_cls_to_ent_cls, rel_cls_to_ent_cls, obj_to_ent, rel_
entity_type_id = 3,
entity_class_id = :entity_class_id,
entity_id = :entity_id
- """
- ),
+ """),
{
"user": user,
"date": date,
diff --git a/spinedb_api/arrow_value.py b/spinedb_api/arrow_value.py
index 7dae65e9..01e68bea 100644
--- a/spinedb_api/arrow_value.py
+++ b/spinedb_api/arrow_value.py
@@ -18,6 +18,7 @@
This is highly experimental API.
"""
+
from collections import defaultdict
from collections.abc import Callable, Iterable
import datetime
diff --git a/spinedb_api/dataframes.py b/spinedb_api/dataframes.py
index 4acc04c0..30af6ad3 100644
--- a/spinedb_api/dataframes.py
+++ b/spinedb_api/dataframes.py
@@ -104,6 +104,7 @@
).subquery()
df = fetch_as_dataframe(db_map, final_query, maps)
"""
+
from __future__ import annotations
import collections
from typing import Any, Union
diff --git a/spinedb_api/db_mapping.py b/spinedb_api/db_mapping.py
index d6aeb4fb..30804c54 100644
--- a/spinedb_api/db_mapping.py
+++ b/spinedb_api/db_mapping.py
@@ -15,6 +15,7 @@
If you're planning to use this class, it is probably a good idea to first familiarize yourself a little bit with the
:ref:`db_mapping_schema`.
"""
+
from __future__ import annotations
from collections.abc import Callable
from datetime import datetime, timezone
@@ -1418,8 +1419,7 @@ def type_(f_dict):
factory = ITEM_CLASS_BY_TYPE[item_type]
a = _a(item_type)
get_kwargs = _kwargs(_uq_fields(factory))
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def {item_type}(self, **kwargs):
"""Returns {a} `{item_type}` item matching the keyword arguments.
@@ -1429,11 +1429,9 @@ def {item_type}(self, **kwargs):
Returns:
:class:`PublicItem`
"""
- '''
- )
+ ''')
children.setdefault("get", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def find_{_pluralize(item_type)}(self, **kwargs):
"""Finds and returns all `{item_type}` items matching the keyword arguments.
@@ -1443,12 +1441,10 @@ def find_{_pluralize(item_type)}(self, **kwargs):
Returns:
list of :class:`PublicItem`: The items.
"""
- '''
- )
+ ''')
children.setdefault("find", []).append(child)
add_kwargs = _kwargs(factory.fields)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def add_{item_type}(self, **kwargs):
"""Adds {a} `{item_type}` item to the in-memory mapping.
@@ -1458,23 +1454,19 @@ def add_{item_type}(self, **kwargs):
Returns:
:class:`PublicItem`: The added item.
"""
- '''
- )
+ ''')
children.setdefault("add", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def add_{_pluralize(item_type)}(self, items):
"""Adds multiple `{item_type}` items to the in-memory mapping.
Args:
items (list of dict): items to add
"""
- '''
- )
+ ''')
children.setdefault("add many", []).append(child)
update_kwargs = f"id (int): The id of the item to update.\n{padding}" + _kwargs(factory.fields)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def update_{item_type}(self, **kwargs):
"""Updates {a} `{item_type}` item in the in-memory mapping.
@@ -1484,22 +1476,18 @@ def update_{item_type}(self, **kwargs):
Returns:
:class:`PublicItem` or None: The updated item or None if nothing was updated.
"""
- '''
- )
+ ''')
children.setdefault("update", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def update_{_pluralize(item_type)}(self, items):
"""Updates multiple `{item_type}` items in the in-memory mapping.
Args:
items (list of dict): items to update
"""
- '''
- )
+ ''')
children.setdefault("update many", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def add_or_update_{item_type}(self, **kwargs):
"""Adds {a} `{item_type}` item to the in-memory mapping if it doesn't exist;
otherwise updates the current one.
@@ -1510,11 +1498,9 @@ def add_or_update_{item_type}(self, **kwargs):
Returns:
:class:`PublicItem` or None: The added or updated item or None if nothing was added or updated.
"""
- '''
- )
+ ''')
children.setdefault("add_or_update", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def add_or_update_{_pluralize(item_type)}(self, items):
"""Adds multiple `{item_type}` items to the in-memory mapping if they don't exist;
otherwise updates the items.
@@ -1522,33 +1508,27 @@ def add_or_update_{_pluralize(item_type)}(self, items):
Args:
items(list of dict): items to add or update
"""
- '''
- )
+ ''')
children.setdefault("add_or_update many", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def remove_{item_type}(self, **kwargs):
"""Removes {a} `{item_type}` item from the in-memory mapping.
Args:
{add_kwargs}
"""
- '''
- )
+ ''')
children.setdefault("remove", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def remove_{_pluralize(item_type)}(self, items):
"""Removes multiple `{item_type}` items from the in-memory mapping.
Args:
items(list of dict): items to remove
"""
- '''
- )
+ ''')
children.setdefault("remove many", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def restore_{item_type}(self, **kwargs):
"""Restores a previously removed `{item_type}` item into the in-memory mapping.
@@ -1558,19 +1538,16 @@ def restore_{item_type}(self, **kwargs):
Returns:
:class:`PublicItem`: The restored item.
"""
- '''
- )
+ ''')
children.setdefault("restore", []).append(child)
- child = astroid.extract_node(
- f'''
+ child = astroid.extract_node(f'''
def restore_{_pluralize(item_type)}(self, items):
"""Restores multiple `{item_type}` items back into the in-memory mapping.
Args:
items(list of dict): items to restore
"""
- '''
- )
+ ''')
children.setdefault("restore many", []).append(child)
for child_list in children.values():
for child in child_list:
diff --git a/spinedb_api/db_mapping_helpers.py b/spinedb_api/db_mapping_helpers.py
index 0f2c7daf..a7bde905 100644
--- a/spinedb_api/db_mapping_helpers.py
+++ b/spinedb_api/db_mapping_helpers.py
@@ -13,6 +13,7 @@
This module defines functions, classes and other utilities
that may be useful with :class:`.db_mapping.DatabaseMapping`.
"""
+
from spinedb_api.db_mapping_base import PublicItem
from spinedb_api.mapped_items import ParameterDefinitionItem
from spinedb_api.parameter_value import UNPARSED_NULL_VALUE, Map, from_database_to_dimension_count, type_for_value
diff --git a/spinedb_api/export_functions.py b/spinedb_api/export_functions.py
index 4480ee1a..c1f1fbe4 100644
--- a/spinedb_api/export_functions.py
+++ b/spinedb_api/export_functions.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Functions for exporting data from a Spine database in a standard format."""
+
from collections.abc import Callable, Iterable, Iterator
from operator import itemgetter
from typing import Any, Optional, TypeAlias, Union
diff --git a/spinedb_api/export_mapping/export_mapping.py b/spinedb_api/export_mapping/export_mapping.py
index 416610d9..d295c985 100644
--- a/spinedb_api/export_mapping/export_mapping.py
+++ b/spinedb_api/export_mapping/export_mapping.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Contains export mappings for database items such as entities, entity classes and parameter values."""
+
from __future__ import annotations
from collections.abc import Callable, Iterator
from contextlib import suppress
diff --git a/spinedb_api/export_mapping/generator.py b/spinedb_api/export_mapping/generator.py
index e8e7ca66..6242f16c 100644
--- a/spinedb_api/export_mapping/generator.py
+++ b/spinedb_api/export_mapping/generator.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Contains generator functions that convert a Spine database into rows of tabular data. """
+"""Contains generator functions that convert a Spine database into rows of tabular data."""
+
from collections.abc import Iterator
from copy import deepcopy
from typing import Any, Optional
diff --git a/spinedb_api/export_mapping/group_functions.py b/spinedb_api/export_mapping/group_functions.py
index 53021e6b..f8eaf9ba 100644
--- a/spinedb_api/export_mapping/group_functions.py
+++ b/spinedb_api/export_mapping/group_functions.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Contains functions to group values in pivot tables with hidden columns or rows. """
+"""Contains functions to group values in pivot tables with hidden columns or rows."""
+
from typing import Any, ClassVar, Type
import numpy as np
diff --git a/spinedb_api/export_mapping/pivot.py b/spinedb_api/export_mapping/pivot.py
index 7a3f326f..1cdd1eca 100644
--- a/spinedb_api/export_mapping/pivot.py
+++ b/spinedb_api/export_mapping/pivot.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Contains functions and methods to turn a regular export table into a pivot table """
+"""Contains functions and methods to turn a regular export table into a pivot table"""
+
from copy import deepcopy
from ..mapping import Position, is_pivoted, is_regular, unflatten, value_index
from .export_mapping import EntityMapping
diff --git a/spinedb_api/export_mapping/settings.py b/spinedb_api/export_mapping/settings.py
index eed32bea..82f26700 100644
--- a/spinedb_api/export_mapping/settings.py
+++ b/spinedb_api/export_mapping/settings.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Contains convenience functions to set up different database export schemes."""
+
from itertools import takewhile
from ..mapping import unflatten
from .export_mapping import (
diff --git a/spinedb_api/filters/alternative_filter.py b/spinedb_api/filters/alternative_filter.py
index 63aaf20a..7de85d7d 100644
--- a/spinedb_api/filters/alternative_filter.py
+++ b/spinedb_api/filters/alternative_filter.py
@@ -15,6 +15,7 @@
Alternative filter is defined by selected alternatives.
It lets everything depending on the selected alternatives through and filters out the rest.
"""
+
from collections.abc import Iterable
from functools import partial
from sqlalchemy import Integer, and_, cast, func, literal, or_, select, union_all
diff --git a/spinedb_api/filters/renamer.py b/spinedb_api/filters/renamer.py
index b97e3409..3f1e75d2 100644
--- a/spinedb_api/filters/renamer.py
+++ b/spinedb_api/filters/renamer.py
@@ -14,6 +14,7 @@
Currently, entity classes and parameter can be renamed.
"""
+
from functools import partial
from sqlalchemy import case
diff --git a/spinedb_api/filters/tools.py b/spinedb_api/filters/tools.py
index 3d17cecc..44b78a05 100644
--- a/spinedb_api/filters/tools.py
+++ b/spinedb_api/filters/tools.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" This module contains tools and utilities to work with filters. """
+"""This module contains tools and utilities to work with filters."""
+
from __future__ import annotations
from collections.abc import Iterable
from itertools import dropwhile, takewhile
diff --git a/spinedb_api/filters/value_transformer.py b/spinedb_api/filters/value_transformer.py
index b10a1c93..db9202c0 100644
--- a/spinedb_api/filters/value_transformer.py
+++ b/spinedb_api/filters/value_transformer.py
@@ -19,6 +19,7 @@
- ``invert`` inverts the value
- ``generate_index`` uses a Python expression to reindex an indexed value
"""
+
from collections.abc import Sequence
from functools import partial
from numbers import Number
diff --git a/spinedb_api/graph_layout_generator.py b/spinedb_api/graph_layout_generator.py
index f52427b2..5043c1a0 100644
--- a/spinedb_api/graph_layout_generator.py
+++ b/spinedb_api/graph_layout_generator.py
@@ -13,6 +13,7 @@
"""
This module defines the :class:`.GraphLayoutGenerator` class.
"""
+
import math
import numpy as np
from numpy import atleast_1d as arr
diff --git a/spinedb_api/import_functions.py b/spinedb_api/import_functions.py
index 8fd1f32b..e200c7d2 100644
--- a/spinedb_api/import_functions.py
+++ b/spinedb_api/import_functions.py
@@ -15,6 +15,7 @@
This functionality is equivalent to the one provided by :meth:`.DatabaseMapping.add_update_item`,
but the syntax is a little more compact.
"""
+
from collections import defaultdict
from collections.abc import Callable, Iterable, Iterator, Sequence
from contextlib import suppress
diff --git a/spinedb_api/import_mapping/generator.py b/spinedb_api/import_mapping/generator.py
index ad8e177d..85776878 100644
--- a/spinedb_api/import_mapping/generator.py
+++ b/spinedb_api/import_mapping/generator.py
@@ -14,6 +14,7 @@
Contains `get_mapped_data()` that converts rows of tabular data into a dictionary for import to a Spine DB,
using ``import_functions.import_data()``
"""
+
from collections.abc import Callable, Iterable
from copy import deepcopy
from itertools import dropwhile
diff --git a/spinedb_api/import_mapping/import_mapping.py b/spinedb_api/import_mapping/import_mapping.py
index 99a709c1..82e68a09 100644
--- a/spinedb_api/import_mapping/import_mapping.py
+++ b/spinedb_api/import_mapping/import_mapping.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Contains import mappings for database items such as entities, entity classes and parameter values."""
+
from __future__ import annotations
from collections.abc import Iterable
from dataclasses import dataclass, field
diff --git a/spinedb_api/import_mapping/import_mapping_compat.py b/spinedb_api/import_mapping/import_mapping_compat.py
index 329e9b2d..441ffcb7 100644
--- a/spinedb_api/import_mapping/import_mapping_compat.py
+++ b/spinedb_api/import_mapping/import_mapping_compat.py
@@ -11,6 +11,7 @@
######################################################################################################################
"""Functions for creating import mappings from dicts."""
+
from ..mapping import to_dict as import_mapping_to_dict
from .import_mapping import (
AlternativeMapping,
diff --git a/spinedb_api/purge.py b/spinedb_api/purge.py
index 33ed2fcf..8f91cbb1 100644
--- a/spinedb_api/purge.py
+++ b/spinedb_api/purge.py
@@ -10,7 +10,8 @@
# this program. If not, see .
######################################################################################################################
-""" Functions to purge DBs. """
+"""Functions to purge DBs."""
+
from .db_mapping import DatabaseMapping
from .exception import NothingToCommit, SpineDBAPIError, SpineDBVersionError
from .filters.tools import clear_filter_configs
diff --git a/spinedb_api/scenario_recipes.py b/spinedb_api/scenario_recipes.py
index f1cea857..91c5a515 100644
--- a/spinedb_api/scenario_recipes.py
+++ b/spinedb_api/scenario_recipes.py
@@ -94,6 +94,7 @@
``coal+coal_chp+wind``, ``coal+coal_chp+antimatter``, ``coal+wind+antimatter``, ``coal_chp+wind+antimatter``
and ``coal+coal_chp+wind+antimatter``
"""
+
from collections.abc import Iterable, Sequence
from spinedb_api import SpineDBAPIError
from spinedb_api.db_mapping_base import PublicItem
diff --git a/spinedb_api/spine_db_client.py b/spinedb_api/spine_db_client.py
index 61fb81a6..7ebee656 100644
--- a/spinedb_api/spine_db_client.py
+++ b/spinedb_api/spine_db_client.py
@@ -11,6 +11,7 @@
######################################################################################################################
"""This module defines the :class:`SpineDBClient` class."""
+
from __future__ import annotations
from collections.abc import Iterator
from contextlib import contextmanager
diff --git a/spinedb_api/spine_io/exporters/csv_writer.py b/spinedb_api/spine_io/exporters/csv_writer.py
index e74b7771..3d3a4bf5 100644
--- a/spinedb_api/spine_io/exporters/csv_writer.py
+++ b/spinedb_api/spine_io/exporters/csv_writer.py
@@ -13,6 +13,7 @@
Module contains a .csv writer implementation.
"""
+
import csv
import os
import os.path
diff --git a/spinedb_api/spine_io/exporters/excel.py b/spinedb_api/spine_io/exporters/excel.py
index fa888fd7..96c8fafb 100644
--- a/spinedb_api/spine_io/exporters/excel.py
+++ b/spinedb_api/spine_io/exporters/excel.py
@@ -14,6 +14,7 @@
Framework for exporting a database to Excel file.
"""
+
from spinedb_api.export_mapping.export_mapping import (
AlternativeDescriptionMapping,
AlternativeMapping,
diff --git a/spinedb_api/spine_io/exporters/excel_writer.py b/spinedb_api/spine_io/exporters/excel_writer.py
index 8aacc29a..a0d9e1e9 100644
--- a/spinedb_api/spine_io/exporters/excel_writer.py
+++ b/spinedb_api/spine_io/exporters/excel_writer.py
@@ -14,6 +14,7 @@
A writer for exporting Spine databases to Excel files.
"""
+
from pathlib import Path
import re
import numpy
diff --git a/spinedb_api/spine_io/exporters/gdx_writer.py b/spinedb_api/spine_io/exporters/gdx_writer.py
index 8cdd88bf..d5d3cb05 100644
--- a/spinedb_api/spine_io/exporters/gdx_writer.py
+++ b/spinedb_api/spine_io/exporters/gdx_writer.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Module contains a .gdx writer implementation. """
+"""Module contains a .gdx writer implementation."""
+
import math
from gams.core import gdx
from gdx2py import GAMSParameter, GAMSScalar, GAMSSet, GdxFile
diff --git a/spinedb_api/spine_io/exporters/sql_writer.py b/spinedb_api/spine_io/exporters/sql_writer.py
index 915113d0..bf28ec18 100644
--- a/spinedb_api/spine_io/exporters/sql_writer.py
+++ b/spinedb_api/spine_io/exporters/sql_writer.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Module contains an SQL writer implementation. """
+"""Module contains an SQL writer implementation."""
+
from sqlalchemy import Boolean, Column, DateTime, Float, Integer, MetaData, String, Table, create_engine
from sqlalchemy.orm import Session
from spinedb_api import parameter_value
diff --git a/spinedb_api/spine_io/exporters/writer.py b/spinedb_api/spine_io/exporters/writer.py
index e261ab27..8fe1075e 100644
--- a/spinedb_api/spine_io/exporters/writer.py
+++ b/spinedb_api/spine_io/exporters/writer.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Module contains the :class:`Writer` base class and functions to write tabular data. """
+"""Module contains the :class:`Writer` base class and functions to write tabular data."""
+
from __future__ import annotations
from contextlib import contextmanager
from copy import copy
diff --git a/spinedb_api/spine_io/gdx_utils.py b/spinedb_api/spine_io/gdx_utils.py
index ebe36970..9b8df2b7 100644
--- a/spinedb_api/spine_io/gdx_utils.py
+++ b/spinedb_api/spine_io/gdx_utils.py
@@ -10,7 +10,7 @@
# this program. If not, see .
######################################################################################################################
-""" Utility functions for .gdx import/export. """
+"""Utility functions for .gdx import/export."""
import os
import re
diff --git a/spinedb_api/spine_io/importers/datapackage_reader.py b/spinedb_api/spine_io/importers/datapackage_reader.py
index 0acb13dc..2df47073 100644
--- a/spinedb_api/spine_io/importers/datapackage_reader.py
+++ b/spinedb_api/spine_io/importers/datapackage_reader.py
@@ -10,7 +10,8 @@
# this program. If not, see .
######################################################################################################################
-""" Contains DataPackageReader class. """
+"""Contains DataPackageReader class."""
+
from itertools import chain
import threading
import frictionless
diff --git a/spinedb_api/spine_io/importers/excel_reader.py b/spinedb_api/spine_io/importers/excel_reader.py
index 506f2041..78bfa7db 100644
--- a/spinedb_api/spine_io/importers/excel_reader.py
+++ b/spinedb_api/spine_io/importers/excel_reader.py
@@ -10,7 +10,7 @@
# this program. If not, see .
######################################################################################################################
-""" Contains ExcelReader class and helper functions. """
+"""Contains ExcelReader class and helper functions."""
import io
from itertools import chain, islice, takewhile
diff --git a/spinedb_api/spine_io/importers/gdx_reader.py b/spinedb_api/spine_io/importers/gdx_reader.py
index 23478f46..8d70569b 100644
--- a/spinedb_api/spine_io/importers/gdx_reader.py
+++ b/spinedb_api/spine_io/importers/gdx_reader.py
@@ -10,7 +10,8 @@
# this program. If not, see .
######################################################################################################################
-""" Contains GDXReader class and a help function. """
+"""Contains GDXReader class and a help function."""
+
from gdx2py import GAMSParameter, GAMSScalar, GAMSSet, GdxFile
from spinedb_api.exception import ReaderError
from ..gdx_utils import find_gams_directory, gams_supports_new_api
diff --git a/spinedb_api/spine_io/importers/json_reader.py b/spinedb_api/spine_io/importers/json_reader.py
index 5f4031ea..4b12b633 100644
--- a/spinedb_api/spine_io/importers/json_reader.py
+++ b/spinedb_api/spine_io/importers/json_reader.py
@@ -10,7 +10,8 @@
# this program. If not, see .
######################################################################################################################
-""" Contains JSONReader class. """
+"""Contains JSONReader class."""
+
import itertools
import os
import sys
diff --git a/spinedb_api/spine_io/importers/reader.py b/spinedb_api/spine_io/importers/reader.py
index 35830a8a..9c31d1ec 100644
--- a/spinedb_api/spine_io/importers/reader.py
+++ b/spinedb_api/spine_io/importers/reader.py
@@ -10,7 +10,8 @@
# this program. If not, see .
######################################################################################################################
-""" Contains a base class for a data source readers used in importing. """
+"""Contains a base class for a data source readers used in importing."""
+
from collections.abc import Callable, Iterator
from dataclasses import dataclass, field
from itertools import islice
diff --git a/spinedb_api/spine_io/importers/sqlalchemy_reader.py b/spinedb_api/spine_io/importers/sqlalchemy_reader.py
index 41289c83..a3e14478 100644
--- a/spinedb_api/spine_io/importers/sqlalchemy_reader.py
+++ b/spinedb_api/spine_io/importers/sqlalchemy_reader.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Contains SQLAlchemyReader class. """
+"""Contains SQLAlchemyReader class."""
+
from sqlalchemy import MetaData, create_engine
from sqlalchemy.orm import Session
from ...exception import ReaderError
diff --git a/tests/__init__.py b/tests/__init__.py
index 84e68460..6ad86b7c 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -10,4 +10,4 @@
# this program. If not, see .
######################################################################################################################
-""" Unit tests package for :mod:`spinedb_api`. """
+"""Unit tests package for :mod:`spinedb_api`."""
diff --git a/tests/export_mapping/test_pivot.py b/tests/export_mapping/test_pivot.py
index 659e0f38..5f2e688b 100644
--- a/tests/export_mapping/test_pivot.py
+++ b/tests/export_mapping/test_pivot.py
@@ -13,6 +13,7 @@
Contains unit tests for the ``pivot`` module.
"""
+
import unittest
import numpy
from spinedb_api.export_mapping.pivot import make_pivot
diff --git a/tests/filters/test_alternative_filter.py b/tests/filters/test_alternative_filter.py
index 9096b504..b274a470 100644
--- a/tests/filters/test_alternative_filter.py
+++ b/tests/filters/test_alternative_filter.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Unit tests for ``alternative_filter`` module. """
+"""Unit tests for ``alternative_filter`` module."""
+
import gc
from pathlib import Path
from tempfile import TemporaryDirectory
diff --git a/tests/filters/test_renamer.py b/tests/filters/test_renamer.py
index 45bd00c0..ab4b0836 100644
--- a/tests/filters/test_renamer.py
+++ b/tests/filters/test_renamer.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for ``renamer`` module."""
+
from pathlib import Path
from tempfile import TemporaryDirectory
import unittest
diff --git a/tests/filters/test_scenario_filter.py b/tests/filters/test_scenario_filter.py
index c8ab1e26..87570409 100644
--- a/tests/filters/test_scenario_filter.py
+++ b/tests/filters/test_scenario_filter.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Unit tests for ``alternative_value_filter`` module. """
+"""Unit tests for ``alternative_value_filter`` module."""
+
from pathlib import Path
from tempfile import TemporaryDirectory
import unittest
diff --git a/tests/filters/test_tools.py b/tests/filters/test_tools.py
index 867d937c..13d7d729 100644
--- a/tests/filters/test_tools.py
+++ b/tests/filters/test_tools.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Unit tests for the ``filters.tools`` module. """
+"""Unit tests for the ``filters.tools`` module."""
+
from datetime import datetime
import os.path
from tempfile import TemporaryDirectory
diff --git a/tests/filters/test_value_transformer.py b/tests/filters/test_value_transformer.py
index 03f502fb..d51923b7 100644
--- a/tests/filters/test_value_transformer.py
+++ b/tests/filters/test_value_transformer.py
@@ -10,7 +10,8 @@
# this program. If not, see .
######################################################################################################################
-""" Unit tests for ``value_transformer`` module. """
+"""Unit tests for ``value_transformer`` module."""
+
from pathlib import Path
from tempfile import TemporaryDirectory
import unittest
diff --git a/tests/import_mapping/test_generator.py b/tests/import_mapping/test_generator.py
index 87c69fe7..11da52f0 100644
--- a/tests/import_mapping/test_generator.py
+++ b/tests/import_mapping/test_generator.py
@@ -11,6 +11,7 @@
######################################################################################################################
"""Contains unit tests for the generator module."""
+
import unittest
from spinedb_api import Array, DateTime, Duration, Map
from spinedb_api.import_mapping.generator import get_mapped_data
diff --git a/tests/import_mapping/test_import_mapping.py b/tests/import_mapping/test_import_mapping.py
index 26c61675..faf318fd 100644
--- a/tests/import_mapping/test_import_mapping.py
+++ b/tests/import_mapping/test_import_mapping.py
@@ -11,6 +11,7 @@
######################################################################################################################
"""Unit tests for import Mappings."""
+
import unittest
from unittest.mock import Mock
from spinedb_api.exception import InvalidMapping, InvalidMappingComponent
diff --git a/tests/spine_io/exporters/test_csv_writer.py b/tests/spine_io/exporters/test_csv_writer.py
index 076e3f98..f1e6bfa0 100644
--- a/tests/spine_io/exporters/test_csv_writer.py
+++ b/tests/spine_io/exporters/test_csv_writer.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for csv writer."""
+
from pathlib import Path
from tempfile import TemporaryDirectory
import unittest
diff --git a/tests/spine_io/exporters/test_excel_writer.py b/tests/spine_io/exporters/test_excel_writer.py
index 3790603e..c58b816c 100644
--- a/tests/spine_io/exporters/test_excel_writer.py
+++ b/tests/spine_io/exporters/test_excel_writer.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for Excel writer."""
+
from itertools import zip_longest
import os.path
from tempfile import TemporaryDirectory
diff --git a/tests/spine_io/exporters/test_gdx_writer.py b/tests/spine_io/exporters/test_gdx_writer.py
index ab51a187..916b7173 100644
--- a/tests/spine_io/exporters/test_gdx_writer.py
+++ b/tests/spine_io/exporters/test_gdx_writer.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for gdx writer."""
+
import math
from pathlib import Path
import sys
diff --git a/tests/spine_io/exporters/test_sql_writer.py b/tests/spine_io/exporters/test_sql_writer.py
index d728edf5..226229f3 100644
--- a/tests/spine_io/exporters/test_sql_writer.py
+++ b/tests/spine_io/exporters/test_sql_writer.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for SQL writer."""
+
from pathlib import Path
from tempfile import TemporaryDirectory
import unittest
diff --git a/tests/spine_io/exporters/test_writer.py b/tests/spine_io/exporters/test_writer.py
index fd9ce5de..4c367169 100644
--- a/tests/spine_io/exporters/test_writer.py
+++ b/tests/spine_io/exporters/test_writer.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for ``writer`` module."""
+
import unittest
from spinedb_api import DatabaseMapping, import_object_classes, import_objects
from spinedb_api.export_mapping.settings import entity_export
diff --git a/tests/spine_io/importers/test_json_reader.py b/tests/spine_io/importers/test_json_reader.py
index 710eb98d..8b67e653 100644
--- a/tests/spine_io/importers/test_json_reader.py
+++ b/tests/spine_io/importers/test_json_reader.py
@@ -10,7 +10,8 @@
# this program. If not, see .
######################################################################################################################
-""" Contains unit tests for JSONReader. """
+"""Contains unit tests for JSONReader."""
+
import json
from pathlib import Path
import pickle
diff --git a/tests/test_DatabaseMapping.py b/tests/test_DatabaseMapping.py
index b08de5e6..508b04aa 100644
--- a/tests/test_DatabaseMapping.py
+++ b/tests/test_DatabaseMapping.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for DatabaseMapping class."""
+
from collections import namedtuple
from datetime import datetime
import gc
diff --git a/tests/test_arrow_value.py b/tests/test_arrow_value.py
index ee758bfa..09580f32 100644
--- a/tests/test_arrow_value.py
+++ b/tests/test_arrow_value.py
@@ -9,7 +9,8 @@
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see .
######################################################################################################################
-""" Unit tests for the `arrow_value` module. """
+"""Unit tests for the `arrow_value` module."""
+
import datetime
import unittest
import pyarrow
diff --git a/tests/test_db_server.py b/tests/test_db_server.py
index ed4b17fc..5e9cfafe 100644
--- a/tests/test_db_server.py
+++ b/tests/test_db_server.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for spine_db_server module."""
+
import os
from tempfile import TemporaryDirectory
import threading
diff --git a/tests/test_export_functions.py b/tests/test_export_functions.py
index c795fd86..4ef752a7 100644
--- a/tests/test_export_functions.py
+++ b/tests/test_export_functions.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for export_functions."""
+
import pathlib
from tempfile import TemporaryDirectory
from spinedb_api import (
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
index c132dfcb..c42293fd 100644
--- a/tests/test_helpers.py
+++ b/tests/test_helpers.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for helpers.py."""
+
import gc
import pathlib
from tempfile import TemporaryDirectory
diff --git a/tests/test_import_functions.py b/tests/test_import_functions.py
index a256ef1c..7267e2f0 100644
--- a/tests/test_import_functions.py
+++ b/tests/test_import_functions.py
@@ -10,6 +10,7 @@
# this program. If not, see .
######################################################################################################################
"""Unit tests for import_functions.py."""
+
import pytest
from spinedb_api.db_mapping import DatabaseMapping
from spinedb_api.exception import NothingToCommit
diff --git a/tests/test_migration.py b/tests/test_migration.py
index f02fcbb2..1140c673 100644
--- a/tests/test_migration.py
+++ b/tests/test_migration.py
@@ -10,7 +10,8 @@
# this program. If not, see .
######################################################################################################################
-""" Unit tests for migration scripts. """
+"""Unit tests for migration scripts."""
+
import os.path
from tempfile import TemporaryDirectory
import unittest
diff --git a/tests/test_parameter_value.py b/tests/test_parameter_value.py
index e91db9e5..929e3ea7 100644
--- a/tests/test_parameter_value.py
+++ b/tests/test_parameter_value.py
@@ -11,6 +11,7 @@
######################################################################################################################
"""Tests for the parameter_value module."""
+
from datetime import datetime
import json
import pickle