From a253b17f8156d81a7ee4ba7de495dac68ab01ea1 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Fri, 5 Jan 2024 09:18:23 +0100 Subject: [PATCH] pre-commit ruff (#2257) Replace black&isort by [ruff](https://docs.astral.sh/ruff/) (faster, additional functionality). * Enable (99%) black-compatible formatting * Enable linting with autofixing * Fix some linting issues * `pre-commit run --all-files` --- .pre-commit-config.yaml | 30 +++++++++---------- documentation/conf.py | 2 +- python/sdist/amici/__init__.py | 11 ++++--- python/sdist/amici/__init__.template.py | 4 +-- python/sdist/amici/de_export.py | 2 +- python/sdist/amici/gradient_check.py | 4 +-- python/sdist/amici/import_utils.py | 6 ++-- python/sdist/amici/petab/util.py | 7 +++-- python/sdist/amici/plotting.py | 3 +- python/sdist/amici/pysb_import.py | 4 +-- python/sdist/amici/sbml_import.py | 9 +++--- python/sdist/amici/sbml_utils.py | 2 +- python/sdist/amici/splines.py | 5 +++- python/sdist/amici/swig_wrappers.py | 2 +- python/sdist/pyproject.toml | 5 ++++ python/tests/conftest.py | 1 - .../lotka_volterra/model/writer.py | 1 - python/tests/test_edata.py | 4 +-- python/tests/test_pysb.py | 1 + tests/conftest.py | 5 +++- .../generateTestConfig/example_steadystate.py | 2 +- 21 files changed, 62 insertions(+), 48 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 521ff54f85..84438209b1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,6 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: -- repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - name: isort (python) - args: ["--profile", "black", "--filter-files", "--line-length", "79"] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: @@ -16,15 +10,21 @@ repos: args: [--allow-multiple-documents] - id: end-of-file-fixer - id: trailing-whitespace -- repo: https://github.com/psf/black - rev: 23.7.0 +- repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.1.11 hooks: - - id: black-jupyter - # It is recommended to specify the latest version of Python - # supported by your project here, or alternatively use - # pre-commit's default_language_version, see - # https://pre-commit.com/#top_level-default_language_version - language_version: python3.11 - args: ["--line-length", "79"] + # Run the linter. + - id: ruff + args: + - --fix + - --config + - python/sdist/pyproject.toml + + # Run the formatter. + - id: ruff-format + args: + - --config + - python/sdist/pyproject.toml exclude: '^(ThirdParty|models)/' diff --git a/documentation/conf.py b/documentation/conf.py index 6576601208..c880530e00 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -5,7 +5,6 @@ # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/stable/config - import os import re import subprocess @@ -18,6 +17,7 @@ import exhale_multiproject_monkeypatch import mock import pandas as pd +import sphinx import sympy as sp from exhale import configs as exhale_configs from sphinx.transforms.post_transforms import ReferencesResolver diff --git a/python/sdist/amici/__init__.py b/python/sdist/amici/__init__.py index 4ee6f05637..b06ea6d0f3 100644 --- a/python/sdist/amici/__init__.py +++ b/python/sdist/amici/__init__.py @@ -107,18 +107,21 @@ def _imported_from_setup() -> bool: # from .swig_wrappers hdf5_enabled = "readSolverSettingsFromHDF5" in dir() # These modules require the swig interface and other dependencies - from .numpy import ExpDataView, ReturnDataView + from .numpy import ExpDataView, ReturnDataView # noqa: F401 from .pandas import * from .swig_wrappers import * # These modules don't require the swig interface from typing import Protocol, runtime_checkable - from .de_export import DEExporter, DEModel - from .sbml_import import SbmlImporter, assignmentRules2observables + from .de_export import DEExporter, DEModel # noqa: F401 + from .sbml_import import ( # noqa: F401 + SbmlImporter, + assignmentRules2observables, + ) @runtime_checkable - class ModelModule(Protocol): + class ModelModule(Protocol): # noqa: F811 """Type of AMICI-generated model modules. To enable static type checking.""" diff --git a/python/sdist/amici/__init__.template.py b/python/sdist/amici/__init__.template.py index c37ac0f962..f5e49b03dd 100644 --- a/python/sdist/amici/__init__.template.py +++ b/python/sdist/amici/__init__.template.py @@ -15,7 +15,7 @@ "version currently installed." ) -from .TPL_MODELNAME import * -from .TPL_MODELNAME import getModel as get_model +from .TPL_MODELNAME import * # noqa: F403, F401 +from .TPL_MODELNAME import getModel as get_model # noqa: F401 __version__ = "TPL_PACKAGE_VERSION" diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index 63c9c05072..dddb748cab 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -587,7 +587,7 @@ def smart_multiply( def smart_is_zero_matrix( - x: Union[sp.MutableDenseMatrix, sp.MutableSparseMatrix] + x: Union[sp.MutableDenseMatrix, sp.MutableSparseMatrix], ) -> bool: """A faster implementation of sympy's is_zero_matrix diff --git a/python/sdist/amici/gradient_check.py b/python/sdist/amici/gradient_check.py index 27e2d671d3..5372fcc853 100644 --- a/python/sdist/amici/gradient_check.py +++ b/python/sdist/amici/gradient_check.py @@ -6,7 +6,7 @@ """ import copy -from typing import Callable, List, Optional, Sequence +from typing import List, Optional, Sequence import numpy as np @@ -331,7 +331,7 @@ def _check_results( """ result = rdata[field] - if type(result) is float: + if type(result) is float: # noqa E721 result = np.array(result) _check_close( diff --git a/python/sdist/amici/import_utils.py b/python/sdist/amici/import_utils.py index 2dfc60d0c5..9f75fcff75 100644 --- a/python/sdist/amici/import_utils.py +++ b/python/sdist/amici/import_utils.py @@ -72,7 +72,7 @@ class ObservableTransformation(str, enum.Enum): def noise_distribution_to_observable_transformation( - noise_distribution: Union[str, Callable] + noise_distribution: Union[str, Callable], ) -> ObservableTransformation: """ Parse noise distribution string and extract observable transformation @@ -93,7 +93,7 @@ def noise_distribution_to_observable_transformation( def noise_distribution_to_cost_function( - noise_distribution: Union[str, Callable] + noise_distribution: Union[str, Callable], ) -> Callable[[str], str]: """ Parse noise distribution string to a cost function definition amici can @@ -423,7 +423,7 @@ def _parse_special_functions(sym: sp.Expr, toplevel: bool = True) -> sp.Expr: def _denest_piecewise( - args: Sequence[Union[sp.Expr, sp.logic.boolalg.Boolean, bool]] + args: Sequence[Union[sp.Expr, sp.logic.boolalg.Boolean, bool]], ) -> Tuple[Union[sp.Expr, sp.logic.boolalg.Boolean, bool]]: """ Denest piecewise functions that contain piecewise as condition diff --git a/python/sdist/amici/petab/util.py b/python/sdist/amici/petab/util.py index d30c1a6e9b..8f309e4071 100644 --- a/python/sdist/amici/petab/util.py +++ b/python/sdist/amici/petab/util.py @@ -1,6 +1,6 @@ """Various helper functions for working with PEtab problems.""" import re -from typing import Dict, Tuple, Union +from typing import TYPE_CHECKING, Dict, Tuple, Union import libsbml import pandas as pd @@ -9,6 +9,9 @@ from petab.mapping import resolve_mapping from petab.models import MODEL_TYPE_PYSB, MODEL_TYPE_SBML +if TYPE_CHECKING: + pysb = None + def get_states_in_condition_table( petab_problem: petab.Problem, @@ -63,7 +66,7 @@ def get_states_in_condition_table( spm = pysb.pattern.SpeciesPatternMatcher( model=petab_problem.model.model ) - except NotImplementedError as e: + except NotImplementedError: raise NotImplementedError( "Requires https://github.com/pysb/pysb/pull/570. " "To use this functionality, update pysb via " diff --git a/python/sdist/amici/plotting.py b/python/sdist/amici/plotting.py index edf4a33156..895f83814a 100644 --- a/python/sdist/amici/plotting.py +++ b/python/sdist/amici/plotting.py @@ -56,8 +56,7 @@ def plot_state_trajectories( elif model is not None and prefer_names: labels = np.asarray(model.getStateNames())[list(state_indices)] labels = [ - l if l else model.getStateIds()[ix] - for ix, l in enumerate(labels) + l if l else model.getStateIds()[ix] for ix, l in enumerate(labels) ] elif model is not None: labels = np.asarray(model.getStateIds())[list(state_indices)] diff --git a/python/sdist/amici/pysb_import.py b/python/sdist/amici/pysb_import.py index aa1dc7cd9b..5862d515a1 100644 --- a/python/sdist/amici/pysb_import.py +++ b/python/sdist/amici/pysb_import.py @@ -410,7 +410,7 @@ def _process_pysb_species(pysb_model: pysb.Model, ode_model: DEModel) -> None: sp.Symbol(f"__s{ix}"), f"{specie}", init, xdot[ix] ) ) - logger.debug(f"Finished Processing PySB species ") + logger.debug("Finished Processing PySB species ") @log_execution_time("processing PySB parameters", logger) @@ -1353,7 +1353,7 @@ def has_fixed_parameter_ic( def extract_monomers( - complex_patterns: Union[pysb.ComplexPattern, List[pysb.ComplexPattern]] + complex_patterns: Union[pysb.ComplexPattern, List[pysb.ComplexPattern]], ) -> List[str]: """ Constructs a list of monomer names contained in complex patterns. diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 124dfc7a63..d8361c04ab 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -21,7 +21,6 @@ List, Optional, Sequence, - Set, Tuple, Union, ) @@ -1165,7 +1164,7 @@ def _process_reactions(self): # accounts for possibly variable compartments. self.stoichiometric_matrix[ species["index"], reaction_index - ] += (sign * stoichiometry * species["conversion_factor"]) + ] += sign * stoichiometry * species["conversion_factor"] if reaction.isSetId(): sym_math = self._local_symbols[reaction.getId()] else: @@ -2360,9 +2359,9 @@ def _replace_in_all_expressions( # rule (at the end of the _process_species method), hence needs to be # processed here too. self.compartments = { - smart_subs(c, old, new) - if replace_identifiers - else c: smart_subs(v, old, self._make_initial(new)) + smart_subs(c, old, new) if replace_identifiers else c: smart_subs( + v, old, self._make_initial(new) + ) for c, v in self.compartments.items() } diff --git a/python/sdist/amici/sbml_utils.py b/python/sdist/amici/sbml_utils.py index 66c9d01bbc..75bcb82a18 100644 --- a/python/sdist/amici/sbml_utils.py +++ b/python/sdist/amici/sbml_utils.py @@ -519,7 +519,7 @@ def mathml2sympy( def _parse_logical_operators( - math_str: Union[str, float, None] + math_str: Union[str, float, None], ) -> Union[str, float, None]: """ Parses a math string in order to replace logical operators by a form diff --git a/python/sdist/amici/splines.py b/python/sdist/amici/splines.py index fdb0912045..657170c2f5 100644 --- a/python/sdist/amici/splines.py +++ b/python/sdist/amici/splines.py @@ -1510,7 +1510,10 @@ def spline_user_functions( "AmiciSplineSensitivity": [ ( lambda *args: True, - lambda spline_id, x, param_id, *p: f"sspl_{spline_ids.index(spline_id)}_{p_index[param_id]}", + lambda spline_id, + x, + param_id, + *p: f"sspl_{spline_ids.index(spline_id)}_{p_index[param_id]}", ) ], } diff --git a/python/sdist/amici/swig_wrappers.py b/python/sdist/amici/swig_wrappers.py index f56f3bd5d2..4983a28f23 100644 --- a/python/sdist/amici/swig_wrappers.py +++ b/python/sdist/amici/swig_wrappers.py @@ -54,7 +54,7 @@ def _capture_cstdout(): def _get_ptr( - obj: Union[AmiciModel, AmiciExpData, AmiciSolver, AmiciReturnData] + obj: Union[AmiciModel, AmiciExpData, AmiciSolver, AmiciReturnData], ) -> Union[ "amici_swig.Model", "amici_swig.ExpData", diff --git a/python/sdist/pyproject.toml b/python/sdist/pyproject.toml index 011064fbdb..91b8484af6 100644 --- a/python/sdist/pyproject.toml +++ b/python/sdist/pyproject.toml @@ -15,3 +15,8 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 79 + +[tool.ruff] +line-length = 79 +ignore = ["E402", "F403", "F405", "E741"] +extend-include = ["*.ipynb"] diff --git a/python/tests/conftest.py b/python/tests/conftest.py index 9ab64b91d7..1da7cb31b3 100644 --- a/python/tests/conftest.py +++ b/python/tests/conftest.py @@ -2,7 +2,6 @@ import copy import importlib import os -import shutil import sys import amici diff --git a/python/tests/petab_test_problems/lotka_volterra/model/writer.py b/python/tests/petab_test_problems/lotka_volterra/model/writer.py index 76b98c3deb..c6abebaebe 100644 --- a/python/tests/petab_test_problems/lotka_volterra/model/writer.py +++ b/python/tests/petab_test_problems/lotka_volterra/model/writer.py @@ -1,6 +1,5 @@ from pathlib import Path -import petab import yaml2sbml yaml2sbml_yaml = "lotka_volterra.yaml" diff --git a/python/tests/test_edata.py b/python/tests/test_edata.py index 9c4d9b9edc..27c67de61e 100644 --- a/python/tests/test_edata.py +++ b/python/tests/test_edata.py @@ -2,11 +2,11 @@ import amici import numpy as np from amici.testing import skip_on_valgrind -from test_sbml_import import model_units_module +from test_sbml_import import model_units_module # noqa: F401 @skip_on_valgrind -def test_edata_sensi_unscaling(model_units_module): +def test_edata_sensi_unscaling(model_units_module): # noqa: F811 """ ExpData parameters should be used for unscaling initial state sensitivities. diff --git a/python/tests/test_pysb.py b/python/tests/test_pysb.py index 52ca3a320f..2911b05fc9 100644 --- a/python/tests/test_pysb.py +++ b/python/tests/test_pysb.py @@ -1,4 +1,5 @@ """PYSB model tests""" +# flake8: noqa: F821 import importlib import logging diff --git a/tests/conftest.py b/tests/conftest.py index 9e90400518..7d98a09abb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,10 +3,13 @@ import re import sys from pathlib import Path -from typing import List, Set, Tuple +from typing import TYPE_CHECKING, List, Set, Tuple import pytest +if TYPE_CHECKING: + from _pytest.reports import TestReport + # stores passed SBML semantic test suite IDs passed_ids = [] diff --git a/tests/generateTestConfig/example_steadystate.py b/tests/generateTestConfig/example_steadystate.py index 07fab49dfe..80e8a776d2 100755 --- a/tests/generateTestConfig/example_steadystate.py +++ b/tests/generateTestConfig/example_steadystate.py @@ -2,7 +2,7 @@ import sys import numpy as np -from example import AmiciExample, dict2attrs +from example import AmiciExample class ExampleSteadystate(AmiciExample):