From 3efd9f961b5d71e204fe04b6cda7cfd56e0a5818 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Mon, 15 Jan 2024 14:42:53 +0100 Subject: [PATCH] pre-commit: run pyupgrade (#2264) Set up pre-commit hook and run [pyupgrade](https://github.com/asottile/pyupgrade) (update type annotations, ...). --- .pre-commit-config.yaml | 7 + documentation/conf.py | 3 +- documentation/recreate_reference_list.py | 2 +- .../amici/conserved_quantities_demartino.py | 41 ++--- .../sdist/amici/conserved_quantities_rref.py | 4 +- python/sdist/amici/cxxcodeprinter.py | 17 +- python/sdist/amici/de_export.py | 154 +++++++++--------- python/sdist/amici/de_model.py | 34 ++-- python/sdist/amici/gradient_check.py | 5 +- python/sdist/amici/import_utils.py | 15 +- python/sdist/amici/numpy.py | 11 +- python/sdist/amici/pandas.py | 34 ++-- python/sdist/amici/petab/conditions.py | 17 +- python/sdist/amici/petab/parameter_mapping.py | 13 +- python/sdist/amici/petab/simulations.py | 19 ++- python/sdist/amici/petab/util.py | 6 +- python/sdist/amici/plotting.py | 3 +- python/sdist/amici/pysb_import.py | 82 +++++----- python/sdist/amici/sbml_import.py | 80 +++++---- python/sdist/amici/sbml_utils.py | 34 ++-- python/sdist/amici/splines.py | 131 +++++++-------- python/sdist/amici/swig.py | 2 +- python/sdist/amici/swig_wrappers.py | 9 +- python/sdist/setup.py | 1 - .../bngwiki_egfr_simple_deletemolecules.py | 1 - python/tests/splines_utils.py | 11 +- python/tests/test_misc.py | 3 +- tests/conftest.py | 6 +- tests/petab_test_suite/conftest.py | 3 +- 29 files changed, 363 insertions(+), 385 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 84438209b1..a2d00e00c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,4 +27,11 @@ repos: - --config - python/sdist/pyproject.toml +- repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + args: ["--py39-plus"] + additional_dependencies: [pyupgrade==3.15.0] + exclude: '^(ThirdParty|models)/' diff --git a/documentation/conf.py b/documentation/conf.py index c880530e00..8b2379a299 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # @@ -15,7 +14,7 @@ import amici import exhale.deploy import exhale_multiproject_monkeypatch -import mock +from unittest import mock import pandas as pd import sphinx import sympy as sp diff --git a/documentation/recreate_reference_list.py b/documentation/recreate_reference_list.py index 034c884c4b..7750173ce1 100755 --- a/documentation/recreate_reference_list.py +++ b/documentation/recreate_reference_list.py @@ -20,7 +20,7 @@ def get_keys_by_year(bibfile): """Get bibtex entry keys as dict by year""" - with open(bibfile, "r") as f: + with open(bibfile) as f: db = biblib.bib.Parser().parse(f, log_fp=sys.stderr).get_entries() recoverer = biblib.messages.InputErrorRecoverer() by_year = {} diff --git a/python/sdist/amici/conserved_quantities_demartino.py b/python/sdist/amici/conserved_quantities_demartino.py index 5b04fa1479..4f2d326b54 100644 --- a/python/sdist/amici/conserved_quantities_demartino.py +++ b/python/sdist/amici/conserved_quantities_demartino.py @@ -2,7 +2,8 @@ import math import random import sys -from typing import List, MutableSequence, Optional, Sequence, Tuple, Union +from typing import Optional, Union +from collections.abc import MutableSequence, Sequence from .logging import get_logger @@ -22,7 +23,7 @@ def compute_moiety_conservation_laws( max_num_monte_carlo: int = 20, rng_seed: Union[None, bool, int] = False, species_names: Optional[Sequence[str]] = None, -) -> Tuple[List[List[int]], List[List[float]]]: +) -> tuple[list[list[int]], list[list[float]]]: """Compute moiety conservation laws. According to the algorithm proposed by De Martino et al. (2014) @@ -112,9 +113,9 @@ def compute_moiety_conservation_laws( def _output( int_kernel_dim: int, kernel_dim: int, - int_matched: List[int], - species_indices: List[List[int]], - species_coefficients: List[List[float]], + int_matched: list[int], + species_indices: list[list[int]], + species_coefficients: list[list[float]], species_names: Optional[Sequence[str]] = None, verbose: bool = False, log_level: int = logging.DEBUG, @@ -203,7 +204,7 @@ def _qsort( def _kernel( stoichiometric_list: Sequence[float], num_species: int, num_reactions: int -) -> Tuple[int, List[int], int, List[int], List[List[int]], List[List[float]]]: +) -> tuple[int, list[int], int, list[int], list[list[int]], list[list[float]]]: """ Kernel (left nullspace of :math:`S`) calculation by Gaussian elimination @@ -227,8 +228,8 @@ def _kernel( kernel dimension, MCLs, integer kernel dimension, integer MCLs and indices to species and reactions in the preceding order as a tuple """ - matrix: List[List[int]] = [[] for _ in range(num_species)] - matrix2: List[List[float]] = [[] for _ in range(num_species)] + matrix: list[list[int]] = [[] for _ in range(num_species)] + matrix2: list[list[float]] = [[] for _ in range(num_species)] i_reaction = 0 i_species = 0 for val in stoichiometric_list: @@ -243,7 +244,7 @@ def _kernel( matrix[i].append(num_reactions + i) matrix2[i].append(1) - order: List[int] = list(range(num_species)) + order: list[int] = list(range(num_species)) pivots = [ matrix[i][0] if len(matrix[i]) else _MAX for i in range(num_species) ] @@ -283,7 +284,7 @@ def _kernel( if pivots[order[j + 1]] == pivots[order[j]] != _MAX: k1 = order[j + 1] k2 = order[j] - column: List[float] = [0] * (num_species + num_reactions) + column: list[float] = [0] * (num_species + num_reactions) g = matrix2[k2][0] / matrix2[k1][0] for i in range(1, len(matrix[k1])): column[matrix[k1][i]] = matrix2[k1][i] * g @@ -369,7 +370,7 @@ def _fill( stoichiometric_list: Sequence[float], matched: Sequence[int], num_species: int, -) -> Tuple[List[List[int]], List[List[int]], List[int]]: +) -> tuple[list[list[int]], list[list[int]], list[int]]: """Construct interaction matrix Construct the interaction matrix out of the given stoichiometric matrix @@ -454,8 +455,8 @@ def _is_linearly_dependent( boolean indicating linear dependence (true) or not (false) """ K = int_kernel_dim + 1 - matrix: List[List[int]] = [[] for _ in range(K)] - matrix2: List[List[float]] = [[] for _ in range(K)] + matrix: list[list[int]] = [[] for _ in range(K)] + matrix2: list[list[float]] = [[] for _ in range(K)] # Populate matrices with species ids and coefficients for CLs for i in range(K - 1): for j in range(len(cls_species_idxs[i])): @@ -508,7 +509,7 @@ def _is_linearly_dependent( if pivots[order[j + 1]] == pivots[order[j]] != _MAX: k1 = order[j + 1] k2 = order[j] - column: List[float] = [0] * num_species + column: list[float] = [0] * num_species g = matrix2[k2][0] / matrix2[k1][0] for i in range(1, len(matrix[k1])): column[matrix[k1][i]] = matrix2[k1][i] * g @@ -540,7 +541,7 @@ def _monte_carlo( initial_temperature: float = 1, cool_rate: float = 1e-3, max_iter: int = 10, -) -> Tuple[bool, int, Sequence[int]]: +) -> tuple[bool, int, Sequence[int]]: """MonteCarlo simulated annealing for finding integer MCLs Finding integer solutions for the MCLs by Monte Carlo, see step (b) in @@ -712,8 +713,8 @@ def _relax( (``False``) """ K = len(int_matched) - matrix: List[List[int]] = [[] for _ in range(K)] - matrix2: List[List[float]] = [[] for _ in range(K)] + matrix: list[list[int]] = [[] for _ in range(K)] + matrix2: list[list[float]] = [[] for _ in range(K)] i_reaction = 0 i_species = 0 for val in stoichiometric_list: @@ -767,7 +768,7 @@ def _relax( if pivots[order[j + 1]] == pivots[order[j]] != _MAX: k1 = order[j + 1] k2 = order[j] - column: List[float] = [0] * num_reactions + column: list[float] = [0] * num_reactions g = matrix2[k2][0] / matrix2[k1][0] for i in range(1, len(matrix[k1])): column[matrix[k1][i]] = matrix2[k1][i] * g @@ -807,7 +808,7 @@ def _relax( # subtract rows # matrix2[k] = matrix2[k] - matrix2[j] * matrix2[k][i] - row_k: List[float] = [0] * num_reactions + row_k: list[float] = [0] * num_reactions for a in range(len(matrix[k])): row_k[matrix[k][a]] = matrix2[k][a] for a in range(len(matrix[j])): @@ -955,7 +956,7 @@ def _reduce( k1 = order[i] for j in range(i + 1, K): k2 = order[j] - column: List[float] = [0] * num_species + column: list[float] = [0] * num_species for species_idx, coefficient in zip( cls_species_idxs[k1], cls_coefficients[k1] ): diff --git a/python/sdist/amici/conserved_quantities_rref.py b/python/sdist/amici/conserved_quantities_rref.py index 46028e94b0..b16053ab08 100644 --- a/python/sdist/amici/conserved_quantities_rref.py +++ b/python/sdist/amici/conserved_quantities_rref.py @@ -1,6 +1,6 @@ """Find conserved quantities deterministically""" -from typing import List, Literal, Optional, Union +from typing import Literal, Optional, Union import numpy as np @@ -67,7 +67,7 @@ def _round(mat): return mat -def pivots(mat: np.array) -> List[int]: +def pivots(mat: np.array) -> list[int]: """Get indices of pivot columns in ``mat``, assumed to be in reduced row echelon form""" pivot_cols = [] diff --git a/python/sdist/amici/cxxcodeprinter.py b/python/sdist/amici/cxxcodeprinter.py index a6ff17e835..3fe5b8cd17 100644 --- a/python/sdist/amici/cxxcodeprinter.py +++ b/python/sdist/amici/cxxcodeprinter.py @@ -2,7 +2,8 @@ import itertools import os import re -from typing import Dict, Iterable, List, Optional, Tuple +from typing import Optional +from collections.abc import Iterable import sympy as sp from sympy.codegen.rewriting import Optimization, optimize @@ -73,7 +74,7 @@ def _print_min_max(self, expr, cpp_fun: str, sympy_fun): ) if len(expr.args) == 1: return self._print(arg0) - return "%s%s(%s, %s)" % ( + return "{}{}({}, {})".format( self._ns, cpp_fun, self._print(arg0), @@ -92,7 +93,7 @@ def _print_Max(self, expr): def _get_sym_lines_array( self, equations: sp.Matrix, variable: str, indent_level: int - ) -> List[str]: + ) -> list[str]: """ Generate C++ code for assigning symbolic terms in symbols to C++ array `variable`. @@ -122,7 +123,7 @@ def _get_sym_lines_symbols( equations: sp.Matrix, variable: str, indent_level: int, - ) -> List[str]: + ) -> list[str]: """ Generate C++ code for where array elements are directly replaced with their corresponding macro symbol @@ -209,11 +210,11 @@ def format_line(symbol: sp.Symbol): def csc_matrix( self, matrix: sp.Matrix, - rownames: List[sp.Symbol], - colnames: List[sp.Symbol], + rownames: list[sp.Symbol], + colnames: list[sp.Symbol], identifier: Optional[int] = 0, pattern_only: Optional[bool] = False, - ) -> Tuple[List[int], List[int], sp.Matrix, List[str], sp.Matrix]: + ) -> tuple[list[int], list[int], sp.Matrix, list[str], sp.Matrix]: """ Generates the sparse symbolic identifiers, symbolic identifiers, sparse matrix, column pointers and row values for a symbolic @@ -298,7 +299,7 @@ def print_bool(expr) -> str: def get_switch_statement( condition: str, - cases: Dict[int, List[str]], + cases: dict[int, list[str]], indentation_level: Optional[int] = 0, indentation_step: Optional[str] = " " * 4, ): diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index dddb748cab..4e7e0999f2 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -25,15 +25,11 @@ TYPE_CHECKING, Any, Callable, - Dict, - List, Literal, Optional, - Sequence, - Set, - Tuple, Union, ) +from collections.abc import Sequence import numpy as np import sympy as sp @@ -757,23 +753,23 @@ def __init__( Whether to cache calls to the simplify method. Can e.g. decrease import times for models with events. """ - self._differential_states: List[DifferentialState] = [] - self._algebraic_states: List[AlgebraicState] = [] - self._algebraic_equations: List[AlgebraicEquation] = [] - self._observables: List[Observable] = [] - self._event_observables: List[EventObservable] = [] - self._sigma_ys: List[SigmaY] = [] - self._sigma_zs: List[SigmaZ] = [] - self._parameters: List[Parameter] = [] - self._constants: List[Constant] = [] - self._log_likelihood_ys: List[LogLikelihoodY] = [] - self._log_likelihood_zs: List[LogLikelihoodZ] = [] - self._log_likelihood_rzs: List[LogLikelihoodRZ] = [] - self._expressions: List[Expression] = [] - self._conservation_laws: List[ConservationLaw] = [] - self._events: List[Event] = [] + self._differential_states: list[DifferentialState] = [] + self._algebraic_states: list[AlgebraicState] = [] + self._algebraic_equations: list[AlgebraicEquation] = [] + self._observables: list[Observable] = [] + self._event_observables: list[EventObservable] = [] + self._sigma_ys: list[SigmaY] = [] + self._sigma_zs: list[SigmaZ] = [] + self._parameters: list[Parameter] = [] + self._constants: list[Constant] = [] + self._log_likelihood_ys: list[LogLikelihoodY] = [] + self._log_likelihood_zs: list[LogLikelihoodZ] = [] + self._log_likelihood_rzs: list[LogLikelihoodRZ] = [] + self._expressions: list[Expression] = [] + self._conservation_laws: list[ConservationLaw] = [] + self._events: list[Event] = [] self.splines = [] - self._symboldim_funs: Dict[str, Callable[[], int]] = { + self._symboldim_funs: dict[str, Callable[[], int]] = { "sx": self.num_states_solver, "v": self.num_states_solver, "vB": self.num_states_solver, @@ -781,23 +777,23 @@ def __init__( "sigmay": self.num_obs, "sigmaz": self.num_eventobs, } - self._eqs: Dict[ + self._eqs: dict[ str, Union[ sp.Matrix, sp.SparseMatrix, - List[Union[sp.Matrix, sp.SparseMatrix]], + list[Union[sp.Matrix, sp.SparseMatrix]], ], ] = dict() - self._sparseeqs: Dict[str, Union[sp.Matrix, List[sp.Matrix]]] = dict() - self._vals: Dict[str, List[sp.Expr]] = dict() - self._names: Dict[str, List[str]] = dict() - self._syms: Dict[str, Union[sp.Matrix, List[sp.Matrix]]] = dict() - self._sparsesyms: Dict[str, Union[List[str], List[List[str]]]] = dict() - self._colptrs: Dict[str, Union[List[int], List[List[int]]]] = dict() - self._rowvals: Dict[str, Union[List[int], List[List[int]]]] = dict() - - self._equation_prototype: Dict[str, Callable] = { + self._sparseeqs: dict[str, Union[sp.Matrix, list[sp.Matrix]]] = dict() + self._vals: dict[str, list[sp.Expr]] = dict() + self._names: dict[str, list[str]] = dict() + self._syms: dict[str, Union[sp.Matrix, list[sp.Matrix]]] = dict() + self._sparsesyms: dict[str, Union[list[str], list[list[str]]]] = dict() + self._colptrs: dict[str, Union[list[int], list[list[int]]]] = dict() + self._rowvals: dict[str, Union[list[int], list[list[int]]]] = dict() + + self._equation_prototype: dict[str, Callable] = { "total_cl": self.conservation_laws, "x0": self.states, "y": self.observables, @@ -809,7 +805,7 @@ def __init__( "sigmay": self.sigma_ys, "sigmaz": self.sigma_zs, } - self._variable_prototype: Dict[str, Callable] = { + self._variable_prototype: dict[str, Callable] = { "tcl": self.conservation_laws, "x_rdata": self.states, "y": self.observables, @@ -821,12 +817,12 @@ def __init__( "sigmaz": self.sigma_zs, "h": self.events, } - self._value_prototype: Dict[str, Callable] = { + self._value_prototype: dict[str, Callable] = { "p": self.parameters, "k": self.constants, } - self._total_derivative_prototypes: Dict[ - str, Dict[str, Union[str, List[str]]] + self._total_derivative_prototypes: dict[ + str, dict[str, Union[str, list[str]]] ] = { "sroot": { "eq": "root", @@ -836,13 +832,13 @@ def __init__( }, } - self._lock_total_derivative: List[str] = list() + self._lock_total_derivative: list[str] = list() self._simplify: Callable = simplify if cache_simplify and simplify is not None: def cached_simplify( expr: sp.Expr, - _simplified: Dict[str, sp.Expr] = {}, + _simplified: dict[str, sp.Expr] = {}, _simplify: Callable = simplify, ) -> sp.Expr: """Speed up expression simplification with caching. @@ -878,59 +874,59 @@ def cached_simplify( for fun in CUSTOM_FUNCTIONS: self._code_printer.known_functions[fun["sympy"]] = fun["c++"] - def differential_states(self) -> List[DifferentialState]: + def differential_states(self) -> list[DifferentialState]: """Get all differential states.""" return self._differential_states - def algebraic_states(self) -> List[AlgebraicState]: + def algebraic_states(self) -> list[AlgebraicState]: """Get all algebraic states.""" return self._algebraic_states - def observables(self) -> List[Observable]: + def observables(self) -> list[Observable]: """Get all observables.""" return self._observables - def parameters(self) -> List[Parameter]: + def parameters(self) -> list[Parameter]: """Get all parameters.""" return self._parameters - def constants(self) -> List[Constant]: + def constants(self) -> list[Constant]: """Get all constants.""" return self._constants - def expressions(self) -> List[Expression]: + def expressions(self) -> list[Expression]: """Get all expressions.""" return self._expressions - def events(self) -> List[Event]: + def events(self) -> list[Event]: """Get all events.""" return self._events - def event_observables(self) -> List[EventObservable]: + def event_observables(self) -> list[EventObservable]: """Get all event observables.""" return self._event_observables - def sigma_ys(self) -> List[SigmaY]: + def sigma_ys(self) -> list[SigmaY]: """Get all observable sigmas.""" return self._sigma_ys - def sigma_zs(self) -> List[SigmaZ]: + def sigma_zs(self) -> list[SigmaZ]: """Get all event observable sigmas.""" return self._sigma_zs - def conservation_laws(self) -> List[ConservationLaw]: + def conservation_laws(self) -> list[ConservationLaw]: """Get all conservation laws.""" return self._conservation_laws - def log_likelihood_ys(self) -> List[LogLikelihoodY]: + def log_likelihood_ys(self) -> list[LogLikelihoodY]: """Get all observable log likelihoodss.""" return self._log_likelihood_ys - def log_likelihood_zs(self) -> List[LogLikelihoodZ]: + def log_likelihood_zs(self) -> list[LogLikelihoodZ]: """Get all event observable log likelihoods.""" return self._log_likelihood_zs - def log_likelihood_rzs(self) -> List[LogLikelihoodRZ]: + def log_likelihood_rzs(self) -> list[LogLikelihoodRZ]: """Get all event observable regularization log likelihoods.""" return self._log_likelihood_rzs @@ -938,7 +934,7 @@ def is_ode(self) -> bool: """Check if model is ODE model.""" return len(self._algebraic_equations) == 0 - def states(self) -> List[State]: + def states(self) -> list[State]: """Get all states.""" return self._differential_states + self._algebraic_states @@ -1265,7 +1261,7 @@ def add_conservation_law( self, state: sp.Symbol, total_abundance: sp.Symbol, - coefficients: Dict[sp.Symbol, sp.Expr], + coefficients: dict[sp.Symbol, sp.Expr], ) -> None: r""" Adds a new conservation law to the model. A conservation law is defined @@ -1331,7 +1327,7 @@ def add_conservation_law( self.add_component(cl) self._differential_states[ix].set_conservation_law(cl) - def get_observable_transformations(self) -> List[ObservableTransformation]: + def get_observable_transformations(self) -> list[ObservableTransformation]: """ List of observable transformations @@ -1460,7 +1456,7 @@ def sym(self, name: str) -> sp.Matrix: return self._syms[name] - def sparsesym(self, name: str, force_generate: bool = True) -> List[str]: + def sparsesym(self, name: str, force_generate: bool = True) -> list[str]: """ Returns (and constructs if necessary) the sparsified identifiers for a sparsified symbolic variable. @@ -1516,7 +1512,7 @@ def sparseeq(self, name) -> sp.Matrix: def colptrs( self, name: str - ) -> Union[List[sp.Number], List[List[sp.Number]]]: + ) -> Union[list[sp.Number], list[list[sp.Number]]]: """ Returns (and constructs if necessary) the column pointers for a sparsified symbolic variable. @@ -1535,7 +1531,7 @@ def colptrs( def rowvals( self, name: str - ) -> Union[List[sp.Number], List[List[sp.Number]]]: + ) -> Union[list[sp.Number], list[list[sp.Number]]]: """ Returns (and constructs if necessary) the row values for a sparsified symbolic variable. @@ -1552,7 +1548,7 @@ def rowvals( self._generate_sparse_symbol(name) return self._rowvals[name] - def val(self, name: str) -> List[sp.Number]: + def val(self, name: str) -> list[sp.Number]: """ Returns (and constructs if necessary) the numeric values of a symbolic entity @@ -1567,7 +1563,7 @@ def val(self, name: str) -> List[sp.Number]: self._generate_value(name) return self._vals[name] - def name(self, name: str) -> List[str]: + def name(self, name: str) -> list[str]: """ Returns (and constructs if necessary) the names of a symbolic variable @@ -1582,7 +1578,7 @@ def name(self, name: str) -> List[str]: self._generate_name(name) return self._names[name] - def free_symbols(self) -> Set[sp.Basic]: + def free_symbols(self) -> set[sp.Basic]: """ Returns list of free symbols that appear in RHS and initial conditions. @@ -1771,7 +1767,7 @@ def parse_events(self) -> None: ) ) - def get_appearance_counts(self, idxs: List[int]) -> List[int]: + def get_appearance_counts(self, idxs: list[int]) -> list[int]: """ Counts how often a state appears in the time derivative of another state and expressions for a subset of states @@ -2275,7 +2271,7 @@ def _compute_equation(self, name: str) -> None: self._eqs[name], self._simplify ) - def sym_names(self) -> List[str]: + def sym_names(self) -> list[str]: """ Returns a list of names of generated symbolic variables @@ -2368,7 +2364,7 @@ def _total_derivative( self, name: str, eq: str, - chainvars: List[str], + chainvars: list[str], var: str, dydx_name: str = None, dxdz_name: str = None, @@ -2507,7 +2503,7 @@ def _multiplication( self._eqs[name] = sign * smart_multiply(xx, yy) def _equation_from_components( - self, name: str, components: List[ModelQuantity] + self, name: str, components: list[ModelQuantity] ) -> None: """ Generates the formulas of a symbolic variable from the attributes @@ -2520,7 +2516,7 @@ def _equation_from_components( """ self._eqs[name] = sp.Matrix([comp.get_val() for comp in components]) - def get_conservation_laws(self) -> List[Tuple[sp.Symbol, sp.Expr]]: + def get_conservation_laws(self) -> list[tuple[sp.Symbol, sp.Expr]]: """Returns a list of states with conservation law set :return: @@ -2597,7 +2593,7 @@ def state_has_conservation_law(self, ix: int) -> bool: """ return self.states()[ix].has_conservation_law() - def get_solver_indices(self) -> Dict[int, int]: + def get_solver_indices(self) -> dict[int, int]: """ Returns a mapping that maps rdata species indices to solver indices @@ -2671,7 +2667,7 @@ def _expr_is_time_dependent(self, expr: sp.Expr) -> bool: def _get_unique_root( self, root_found: sp.Expr, - roots: List[Event], + roots: list[Event], ) -> Union[sp.Symbol, None]: """ Collects roots of Heaviside functions and events and stores them in @@ -2709,7 +2705,7 @@ def _get_unique_root( def _collect_heaviside_roots( self, args: Sequence[sp.Expr], - ) -> List[sp.Expr]: + ) -> list[sp.Expr]: """ Recursively checks an expression for the occurrence of Heaviside functions and return all roots found @@ -2746,7 +2742,7 @@ def _collect_heaviside_roots( def _process_heavisides( self, dxdt: sp.Expr, - roots: List[Event], + roots: list[Event], ) -> sp.Expr: """ Parses the RHS of a state variable, checks for Heaviside functions, @@ -2901,7 +2897,7 @@ def __init__( ) # To only generate a subset of functions, apply subselection here - self.functions: Dict[str, _FunctionInfo] = copy.deepcopy(functions) + self.functions: dict[str, _FunctionInfo] = copy.deepcopy(functions) self.allow_reinit_fixpar_initcond: bool = allow_reinit_fixpar_initcond self._build_hints = set() @@ -3079,7 +3075,7 @@ def _generate_m_code(self) -> None: with open(compile_script, "w") as fileout: fileout.write("\n".join(lines)) - def _get_index(self, name: str) -> Dict[sp.Symbol, int]: + def _get_index(self, name: str) -> dict[sp.Symbol, int]: """ Compute indices for a symbolic array. :param name: @@ -3286,7 +3282,7 @@ def _write_function_file(self, function: str) -> None: def _generate_function_index( self, function: str, indextype: Literal["colptrs", "rowvals"] - ) -> List[str]: + ) -> list[str]: """ Generate equations and C++ code for the function ``function``. @@ -3388,7 +3384,7 @@ def _generate_function_index( def _get_function_body( self, function: str, equations: sp.Matrix - ) -> List[str]: + ) -> list[str]: """ Generate C++ code for body of function ``function``. @@ -3773,11 +3769,9 @@ def _write_model_header_cpp(self) -> None: "Z2EVENT": ", ".join(map(str, self.model._z2event)), "STATE_INDEPENDENT_EVENTS": self._get_state_independent_event_intializer(), "ID": ", ".join( - ( - str(float(isinstance(s, DifferentialState))) - for s in self.model.states() - if not s.has_conservation_law() - ) + str(float(isinstance(s, DifferentialState))) + for s in self.model.states() + if not s.has_conservation_law() ), } @@ -4043,7 +4037,7 @@ class TemplateAmici(Template): def apply_template( source_file: Union[str, Path], target_file: Union[str, Path], - template_data: Dict[str, str], + template_data: dict[str, str], ) -> None: """ Load source file, apply template substitution as provided in diff --git a/python/sdist/amici/de_model.py b/python/sdist/amici/de_model.py index 72ce4a95ba..c20509407a 100644 --- a/python/sdist/amici/de_model.py +++ b/python/sdist/amici/de_model.py @@ -1,7 +1,7 @@ """Objects for AMICI's internal differential equation model representation""" import abc import numbers -from typing import Dict, Optional, Set, SupportsFloat, Union +from typing import Optional, SupportsFloat, Union import sympy as sp @@ -138,7 +138,7 @@ def __init__( identifier: sp.Symbol, name: str, value: sp.Expr, - coefficients: Dict[sp.Symbol, sp.Expr], + coefficients: dict[sp.Symbol, sp.Expr], state_id: sp.Symbol, ): """ @@ -160,9 +160,9 @@ def __init__( identifier of the state that this conservation law replaces """ self._state_expr: sp.Symbol = identifier - (value - state_id) - self._coefficients: Dict[sp.Symbol, sp.Expr] = coefficients + self._coefficients: dict[sp.Symbol, sp.Expr] = coefficients self._ncoeff: sp.Expr = coefficients[state_id] - super(ConservationLaw, self).__init__(identifier, name, value) + super().__init__(identifier, name, value) def get_ncoeff(self, state_id) -> Union[sp.Expr, int, float]: """ @@ -201,9 +201,7 @@ def __init__(self, identifier: str, value: sp.Expr): formula of the algebraic equation, solution is given by ``formula == 0`` """ - super(AlgebraicEquation, self).__init__( - sp.Symbol(identifier), identifier, value - ) + super().__init__(sp.Symbol(identifier), identifier, value) def get_free_symbols(self): return self._value.free_symbols @@ -272,7 +270,7 @@ def __init__(self, identifier: sp.Symbol, name: str, init: sp.Expr): :param init: initial value of the AlgebraicState """ - super(AlgebraicState, self).__init__(identifier, name, init) + super().__init__(identifier, name, init) def has_conservation_law(self): """ @@ -322,7 +320,7 @@ def __init__( :param dt: time derivative """ - super(DifferentialState, self).__init__(identifier, name, init) + super().__init__(identifier, name, init) self._dt = cast_to_sym(dt, "dt") self._conservation_law: Union[ConservationLaw, None] = None @@ -363,7 +361,7 @@ def get_dt(self) -> sp.Expr: """ return self._dt - def get_free_symbols(self) -> Set[sp.Basic]: + def get_free_symbols(self) -> set[sp.Basic]: """ Gets the set of free symbols in time derivative and initial conditions @@ -423,7 +421,7 @@ def __init__( observable transformation, only applies when evaluating objective function or residuals """ - super(Observable, self).__init__(identifier, name, value) + super().__init__(identifier, name, value) self._measurement_symbol = measurement_symbol self._regularization_symbol = None self.trafo = transformation @@ -481,7 +479,7 @@ def __init__( :param event: Symbolic identifier of the corresponding event. """ - super(EventObservable, self).__init__( + super().__init__( identifier, name, value, measurement_symbol, transformation ) self._event: sp.Symbol = event @@ -520,7 +518,7 @@ def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): raise RuntimeError( "This class is meant to be sub-classed, not used directly." ) - super(Sigma, self).__init__(identifier, name, value) + super().__init__(identifier, name, value) class SigmaY(Sigma): @@ -556,7 +554,7 @@ def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): :param value: formula """ - super(Expression, self).__init__(identifier, name, value) + super().__init__(identifier, name, value) class Parameter(ModelQuantity): @@ -581,7 +579,7 @@ def __init__( :param value: numeric value """ - super(Parameter, self).__init__(identifier, name, value) + super().__init__(identifier, name, value) class Constant(ModelQuantity): @@ -605,7 +603,7 @@ def __init__( :param value: numeric value """ - super(Constant, self).__init__(identifier, name, value) + super().__init__(identifier, name, value) class LogLikelihood(ModelQuantity): @@ -634,7 +632,7 @@ def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): raise RuntimeError( "This class is meant to be sub-classed, not used directly." ) - super(LogLikelihood, self).__init__(identifier, name, value) + super().__init__(identifier, name, value) class LogLikelihoodY(LogLikelihood): @@ -692,7 +690,7 @@ def __init__( initial boolean value of the trigger function at t0. If set to `False`, events may trigger at ``t==t0``, otherwise not. """ - super(Event, self).__init__(identifier, name, value) + super().__init__(identifier, name, value) # add the Event specific components self._state_update = state_update self._initial_value = initial_value diff --git a/python/sdist/amici/gradient_check.py b/python/sdist/amici/gradient_check.py index 5372fcc853..c5ddb03749 100644 --- a/python/sdist/amici/gradient_check.py +++ b/python/sdist/amici/gradient_check.py @@ -6,7 +6,8 @@ """ import copy -from typing import List, Optional, Sequence +from typing import Optional +from collections.abc import Sequence import numpy as np @@ -29,7 +30,7 @@ def check_finite_difference( solver: Solver, edata: ExpData, ip: int, - fields: List[str], + fields: list[str], atol: Optional[float] = 1e-4, rtol: Optional[float] = 1e-4, epsilon: Optional[float] = 1e-3, diff --git a/python/sdist/amici/import_utils.py b/python/sdist/amici/import_utils.py index 9f75fcff75..63a160c1de 100644 --- a/python/sdist/amici/import_utils.py +++ b/python/sdist/amici/import_utils.py @@ -7,14 +7,11 @@ from typing import ( Any, Callable, - Dict, - Iterable, Optional, - Sequence, SupportsFloat, - Tuple, Union, ) +from collections.abc import Iterable, Sequence import sympy as sp from sympy.functions.elementary.piecewise import ExprCondPair @@ -33,7 +30,7 @@ class SBMLException(Exception): pass -SymbolDef = Dict[sp.Symbol, Union[Dict[str, sp.Expr], sp.Expr]] +SymbolDef = dict[sp.Symbol, Union[dict[str, sp.Expr], sp.Expr]] # Monkey-patch toposort CircularDependencyError to handle non-sortable objects, @@ -44,13 +41,13 @@ def __init__(self, data): # error messages. That's convenient for doctests. s = "Circular dependencies exist among these items: {{{}}}".format( ", ".join( - "{!r}:{!r}".format(key, value) + f"{key!r}:{value!r}" for key, value in sorted( {str(k): v for k, v in data.items()}.items() ) ) ) - super(CircularDependencyError, self).__init__(s) + super().__init__(s) self.data = data @@ -424,7 +421,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]], -) -> Tuple[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 @@ -548,7 +545,7 @@ def _parse_heaviside_trigger(trigger: sp.Expr) -> sp.Expr: def grouper( iterable: Iterable, n: int, fillvalue: Any = None -) -> Iterable[Tuple[Any]]: +) -> Iterable[tuple[Any]]: """ Collect data into fixed-length chunks or blocks diff --git a/python/sdist/amici/numpy.py b/python/sdist/amici/numpy.py index b259aca2a0..fdf802147c 100644 --- a/python/sdist/amici/numpy.py +++ b/python/sdist/amici/numpy.py @@ -7,7 +7,8 @@ import collections import copy import itertools -from typing import Dict, Iterator, List, Literal, Union +from typing import Literal, Union +from collections.abc import Iterator import amici import numpy as np @@ -33,8 +34,8 @@ class is memory efficient as copies of the underlying C++ objects is """ _swigptr = None - _field_names: List[str] = [] - _field_dimensions: Dict[str, List[int]] = dict() + _field_names: list[str] = [] + _field_dimensions: dict[str, list[int]] = dict() def __getitem__(self, item: str) -> Union[np.ndarray, float]: """ @@ -93,7 +94,7 @@ def __init__(self, swigptr): """ self._swigptr = swigptr self._cache = {} - super(SwigPtrView, self).__init__() + super().__init__() def __len__(self) -> int: """ @@ -421,7 +422,7 @@ def __init__(self, edata: Union[ExpDataPtr, ExpData]): def _field_as_numpy( - field_dimensions: Dict[str, List[int]], field: str, data: SwigPtrView + field_dimensions: dict[str, list[int]], field: str, data: SwigPtrView ) -> Union[np.ndarray, float, None]: """ Convert data object field to numpy array with dimensions according to diff --git a/python/sdist/amici/pandas.py b/python/sdist/amici/pandas.py index 8a2eb5049d..745cbfb767 100644 --- a/python/sdist/amici/pandas.py +++ b/python/sdist/amici/pandas.py @@ -7,7 +7,7 @@ import copy import math -from typing import Dict, List, Optional, SupportsFloat, Union +from typing import Optional, SupportsFloat, Union import amici import numpy as np @@ -25,17 +25,17 @@ ] ExpDatas = Union[ - List[amici.amici.ExpData], - List[amici.ExpDataPtr], + list[amici.amici.ExpData], + list[amici.ExpDataPtr], amici.amici.ExpData, amici.ExpDataPtr, ] -ReturnDatas = Union[List[amici.ReturnDataView], amici.ReturnDataView] +ReturnDatas = Union[list[amici.ReturnDataView], amici.ReturnDataView] AmiciModel = Union[amici.ModelPtr, amici.Model] -def _process_edata_list(edata_list: ExpDatas) -> List[amici.amici.ExpData]: +def _process_edata_list(edata_list: ExpDatas) -> list[amici.amici.ExpData]: """ Maps single instances of :class:`amici.amici.ExpData` to lists of :class:`amici.amici.ExpData` @@ -52,7 +52,7 @@ def _process_edata_list(edata_list: ExpDatas) -> List[amici.amici.ExpData]: return edata_list -def _process_rdata_list(rdata_list: ReturnDatas) -> List[amici.ReturnDataView]: +def _process_rdata_list(rdata_list: ReturnDatas) -> list[amici.ReturnDataView]: """ Maps single instances of :class:`amici.ReturnData` to lists of :class:`amici.ReturnData` @@ -359,11 +359,11 @@ def getResidualsAsDataFrame( def _fill_conditions_dict( - datadict: Dict[str, float], + datadict: dict[str, float], model: AmiciModel, edata: amici.amici.ExpData, by_id: bool, -) -> Dict[str, float]: +) -> dict[str, float]: """ Helper function that fills in condition parameters from model and edata. @@ -413,7 +413,7 @@ def _fill_conditions_dict( return datadict -def _get_extended_observable_cols(model: AmiciModel, by_id: bool) -> List[str]: +def _get_extended_observable_cols(model: AmiciModel, by_id: bool) -> list[str]: """ Construction helper for extended observable dataframe headers. @@ -446,7 +446,7 @@ def _get_extended_observable_cols(model: AmiciModel, by_id: bool) -> List[str]: ) -def _get_observable_cols(model: AmiciModel, by_id: bool) -> List[str]: +def _get_observable_cols(model: AmiciModel, by_id: bool) -> list[str]: """ Construction helper for observable dataframe headers. @@ -475,7 +475,7 @@ def _get_observable_cols(model: AmiciModel, by_id: bool) -> List[str]: ) -def _get_state_cols(model: AmiciModel, by_id: bool) -> List[str]: +def _get_state_cols(model: AmiciModel, by_id: bool) -> list[str]: """ Construction helper for state dataframe headers. @@ -504,7 +504,7 @@ def _get_state_cols(model: AmiciModel, by_id: bool) -> List[str]: ) -def _get_expression_cols(model: AmiciModel, by_id: bool) -> List[str]: +def _get_expression_cols(model: AmiciModel, by_id: bool) -> list[str]: """Construction helper for expression dataframe headers. :param model: @@ -534,7 +534,7 @@ def _get_expression_cols(model: AmiciModel, by_id: bool) -> List[str]: def _get_names_or_ids( model: AmiciModel, variable: str, by_id: bool -) -> List[str]: +) -> list[str]: """ Obtains a unique list of identifiers for the specified variable. First tries model.getVariableNames and then uses model.getVariableIds. @@ -592,10 +592,10 @@ def _get_names_or_ids( def _get_specialized_fixed_parameters( model: AmiciModel, - condition: Union[Dict[str, SupportsFloat], pd.Series], - overwrite: Union[Dict[str, SupportsFloat], pd.Series], + condition: Union[dict[str, SupportsFloat], pd.Series], + overwrite: Union[dict[str, SupportsFloat], pd.Series], by_id: bool, -) -> List[float]: +) -> list[float]: """ Copies values in condition and overwrites them according to key value pairs specified in overwrite. @@ -730,7 +730,7 @@ def constructEdataFromDataFrame( def getEdataFromDataFrame( model: AmiciModel, df: pd.DataFrame, by_id: Optional[bool] = False -) -> List[amici.amici.ExpData]: +) -> list[amici.amici.ExpData]: """ Constructs a ExpData instances according to the provided Model and DataFrame. diff --git a/python/sdist/amici/petab/conditions.py b/python/sdist/amici/petab/conditions.py index 5b9d87e5cf..3347b35ab8 100644 --- a/python/sdist/amici/petab/conditions.py +++ b/python/sdist/amici/petab/conditions.py @@ -2,7 +2,8 @@ import logging import numbers import warnings -from typing import Dict, Sequence, Union +from typing import Union +from collections.abc import Sequence import amici import numpy as np @@ -29,8 +30,8 @@ logger = logging.getLogger(__name__) -SingleParameterMapping = Dict[str, Union[numbers.Number, str]] -SingleScaleMapping = Dict[str, str] +SingleParameterMapping = dict[str, Union[numbers.Number, str]] +SingleScaleMapping = dict[str, str] def fill_in_parameters( @@ -79,7 +80,7 @@ def fill_in_parameters( def fill_in_parameters_for_condition( edata: amici.ExpData, - problem_parameters: Dict[str, numbers.Number], + problem_parameters: dict[str, numbers.Number], scaled_parameters: bool, parameter_mapping: ParameterMappingForCondition, amici_model: AmiciModel, @@ -214,10 +215,10 @@ def _get_par(model_par, value, mapping): def create_parameterized_edatas( amici_model: AmiciModel, petab_problem: petab.Problem, - problem_parameters: Dict[str, numbers.Number], + problem_parameters: dict[str, numbers.Number], scaled_parameters: bool = False, parameter_mapping: ParameterMapping = None, - simulation_conditions: Union[pd.DataFrame, Dict] = None, + simulation_conditions: Union[pd.DataFrame, dict] = None, ) -> list[amici.ExpData]: """Create list of :class:amici.ExpData objects with parameters filled in. @@ -283,7 +284,7 @@ def create_parameterized_edatas( def create_edata_for_condition( - condition: Union[Dict, pd.Series], + condition: Union[dict, pd.Series], measurement_df: pd.DataFrame, amici_model: AmiciModel, petab_problem: petab.Problem, @@ -368,7 +369,7 @@ def create_edata_for_condition( def create_edatas( amici_model: AmiciModel, petab_problem: petab.Problem, - simulation_conditions: Union[pd.DataFrame, Dict] = None, + simulation_conditions: Union[pd.DataFrame, dict] = None, ) -> list[amici.ExpData]: """Create list of :class:`amici.amici.ExpData` objects for PEtab problem. diff --git a/python/sdist/amici/petab/parameter_mapping.py b/python/sdist/amici/petab/parameter_mapping.py index a5a5d6e867..9c527f0395 100644 --- a/python/sdist/amici/petab/parameter_mapping.py +++ b/python/sdist/amici/petab/parameter_mapping.py @@ -21,7 +21,8 @@ import re from collections.abc import Sequence from itertools import chain -from typing import Any, Collection, Iterator, Union +from typing import Any, Union +from collections.abc import Collection, Iterator import amici import numpy as np @@ -164,7 +165,7 @@ def __iter__(self): def __getitem__( self, item - ) -> Union[ParameterMapping, ParameterMappingForCondition]: + ) -> ParameterMapping | ParameterMappingForCondition: result = self.parameter_mappings[item] if isinstance(result, ParameterMappingForCondition): return result @@ -306,7 +307,7 @@ def unscale_parameters_dict( def create_parameter_mapping( petab_problem: petab.Problem, - simulation_conditions: Union[pd.DataFrame, list[dict]], + simulation_conditions: pd.DataFrame | list[dict], scaled_parameters: bool, amici_model: AmiciModel, **parameter_mapping_kwargs, @@ -396,7 +397,7 @@ def create_parameter_mapping( def create_parameter_mapping_for_condition( parameter_mapping_for_condition: petab.ParMappingDictQuadruple, - condition: Union[pd.Series, dict], + condition: pd.Series | dict, petab_problem: petab.Problem, amici_model: AmiciModel, ) -> ParameterMappingForCondition: @@ -631,7 +632,7 @@ def _subset_dict( def _get_initial_state_sbml( petab_problem: petab.Problem, element_id: str -) -> Union[float, sp.Basic]: +) -> float | sp.Basic: import libsbml element = petab_problem.sbml_model.getElementBySId(element_id) @@ -672,7 +673,7 @@ def _get_initial_state_sbml( def _get_initial_state_pysb( petab_problem: petab.Problem, element_id: str -) -> Union[float, sp.Symbol]: +) -> float | sp.Symbol: species_idx = int(re.match(r"__s(\d+)$", element_id)[1]) species_pattern = petab_problem.model.model.species[species_idx] from pysb.pattern import match_complex_pattern diff --git a/python/sdist/amici/petab/simulations.py b/python/sdist/amici/petab/simulations.py index bc42ebcfd3..4078eff8fa 100644 --- a/python/sdist/amici/petab/simulations.py +++ b/python/sdist/amici/petab/simulations.py @@ -5,7 +5,8 @@ """ import copy import logging -from typing import Any, Dict, List, Optional, Sequence, Union +from typing import Any, Optional, Union +from collections.abc import Sequence import amici import numpy as np @@ -72,16 +73,16 @@ def simulate_petab( petab_problem: petab.Problem, amici_model: AmiciModel, solver: Optional[amici.Solver] = None, - problem_parameters: Optional[Dict[str, float]] = None, - simulation_conditions: Union[pd.DataFrame, Dict] = None, - edatas: List[AmiciExpData] = None, + problem_parameters: Optional[dict[str, float]] = None, + simulation_conditions: Union[pd.DataFrame, dict] = None, + edatas: list[AmiciExpData] = None, parameter_mapping: ParameterMapping = None, scaled_parameters: Optional[bool] = False, log_level: int = logging.WARNING, num_threads: int = 1, failfast: bool = True, scaled_gradients: bool = False, -) -> Dict[str, Any]: +) -> dict[str, Any]: """Simulate PEtab model. .. note:: @@ -242,10 +243,10 @@ def aggregate_sllh( amici_model: AmiciModel, rdatas: Sequence[amici.ReturnDataView], parameter_mapping: Optional[ParameterMapping], - edatas: List[AmiciExpData], + edatas: list[AmiciExpData], petab_scale: bool = True, petab_problem: petab.Problem = None, -) -> Union[None, Dict[str, float]]: +) -> Union[None, dict[str, float]]: """ Aggregate likelihood gradient for all conditions, according to PEtab parameter mapping. @@ -464,9 +465,9 @@ def rdatas_to_simulation_df( def _default_scaled_parameters( petab_problem: petab.Problem, - problem_parameters: Optional[Dict[str, float]] = None, + problem_parameters: Optional[dict[str, float]] = None, scaled_parameters: bool = False, -) -> Optional[Dict[str, float]]: +) -> Optional[dict[str, float]]: """ Helper method to handle an unscaled or unspecified parameter vector. diff --git a/python/sdist/amici/petab/util.py b/python/sdist/amici/petab/util.py index 8f309e4071..742f7bdfe3 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 TYPE_CHECKING, Dict, Tuple, Union +from typing import TYPE_CHECKING, Union import libsbml import pandas as pd @@ -15,9 +15,9 @@ def get_states_in_condition_table( petab_problem: petab.Problem, - condition: Union[Dict, pd.Series] = None, + condition: Union[dict, pd.Series] = None, return_patterns: bool = False, -) -> Dict[str, Tuple[Union[float, str, None], Union[float, str, None]]]: +) -> dict[str, tuple[Union[float, str, None], Union[float, str, None]]]: """Get states and their initial condition as specified in the condition table. Returns: Dictionary: ``stateId -> (initial condition simulation, initial condition preequilibration)`` diff --git a/python/sdist/amici/plotting.py b/python/sdist/amici/plotting.py index 895f83814a..25607638d7 100644 --- a/python/sdist/amici/plotting.py +++ b/python/sdist/amici/plotting.py @@ -3,7 +3,8 @@ -------- Plotting related functions """ -from typing import Iterable, Optional, Sequence, Union +from typing import Optional, Union +from collections.abc import Iterable, Sequence import matplotlib.pyplot as plt import numpy as np diff --git a/python/sdist/amici/pysb_import.py b/python/sdist/amici/pysb_import.py index 5862d515a1..4f843033f1 100644 --- a/python/sdist/amici/pysb_import.py +++ b/python/sdist/amici/pysb_import.py @@ -13,14 +13,10 @@ from typing import ( Any, Callable, - Dict, - Iterable, - List, Optional, - Set, - Tuple, Union, ) +from collections.abc import Iterable import numpy as np import pysb @@ -49,8 +45,8 @@ ) from .logging import get_logger, log_execution_time, set_log_level -CL_Prototype = Dict[str, Dict[str, Any]] -ConservationLaw = Dict[str, Union[Dict, str, sp.Basic]] +CL_Prototype = dict[str, dict[str, Any]] +ConservationLaw = dict[str, Union[dict, str, sp.Basic]] logger = get_logger(__name__, logging.ERROR) @@ -58,10 +54,10 @@ def pysb2amici( model: pysb.Model, output_dir: Optional[Union[str, Path]] = None, - observables: List[str] = None, - constant_parameters: List[str] = None, - sigmas: Dict[str, str] = None, - noise_distributions: Optional[Dict[str, Union[str, Callable]]] = None, + observables: list[str] = None, + constant_parameters: list[str] = None, + sigmas: dict[str, str] = None, + noise_distributions: Optional[dict[str, Union[str, Callable]]] = None, verbose: Union[int, bool] = False, assume_pow_positivity: bool = False, compiler: str = None, @@ -191,10 +187,10 @@ def pysb2amici( @log_execution_time("creating ODE model", logger) def ode_model_from_pysb_importer( model: pysb.Model, - constant_parameters: List[str] = None, - observables: List[str] = None, - sigmas: Dict[str, str] = None, - noise_distributions: Optional[Dict[str, Union[str, Callable]]] = None, + constant_parameters: list[str] = None, + observables: list[str] = None, + sigmas: dict[str, str] = None, + noise_distributions: Optional[dict[str, Union[str, Callable]]] = None, compute_conservation_laws: bool = True, simplify: Callable = sp.powsimp, # Do not enable by default without testing. @@ -285,7 +281,7 @@ def ode_model_from_pysb_importer( @log_execution_time("processing PySB stoich. matrix", logger) def _process_stoichiometric_matrix( - pysb_model: pysb.Model, ode_model: DEModel, constant_parameters: List[str] + pysb_model: pysb.Model, ode_model: DEModel, constant_parameters: list[str] ) -> None: """ Exploits the PySB stoichiometric matrix to generate xdot derivatives @@ -415,7 +411,7 @@ def _process_pysb_species(pysb_model: pysb.Model, ode_model: DEModel) -> None: @log_execution_time("processing PySB parameters", logger) def _process_pysb_parameters( - pysb_model: pysb.Model, ode_model: DEModel, constant_parameters: List[str] + pysb_model: pysb.Model, ode_model: DEModel, constant_parameters: list[str] ) -> None: """ Converts pysb parameters into Parameters or Constants and adds them to @@ -443,9 +439,9 @@ def _process_pysb_parameters( def _process_pysb_expressions( pysb_model: pysb.Model, ode_model: DEModel, - observables: List[str], - sigmas: Dict[str, str], - noise_distributions: Optional[Dict[str, Union[str, Callable]]] = None, + observables: list[str], + sigmas: dict[str, str], + noise_distributions: Optional[dict[str, Union[str, Callable]]] = None, ) -> None: r""" Converts pysb expressions/observables into Observables (with @@ -508,9 +504,9 @@ def _add_expression( expr: sp.Basic, pysb_model: pysb.Model, ode_model: DEModel, - observables: List[str], - sigmas: Dict[str, str], - noise_distributions: Optional[Dict[str, Union[str, Callable]]] = None, + observables: list[str], + sigmas: dict[str, str], + noise_distributions: Optional[dict[str, Union[str, Callable]]] = None, ): """ Adds expressions to the ODE model given and adds observables/sigmas if @@ -579,8 +575,8 @@ def _add_expression( def _get_sigma_name_and_value( - pysb_model: pysb.Model, obs_name: str, sigmas: Dict[str, str] -) -> Tuple[str, sp.Basic]: + pysb_model: pysb.Model, obs_name: str, sigmas: dict[str, str] +) -> tuple[str, sp.Basic]: """ Tries to extract standard deviation symbolic identifier and formula for a given observable name from the pysb model and if no specification is @@ -623,9 +619,9 @@ def _get_sigma_name_and_value( def _process_pysb_observables( pysb_model: pysb.Model, ode_model: DEModel, - observables: List[str], - sigmas: Dict[str, str], - noise_distributions: Optional[Dict[str, Union[str, Callable]]] = None, + observables: list[str], + sigmas: dict[str, str], + noise_distributions: Optional[dict[str, Union[str, Callable]]] = None, ) -> None: """ Converts :class:`pysb.core.Observable` into @@ -704,7 +700,7 @@ def _process_pysb_conservation_laws( def _compute_monomers_with_fixed_initial_conditions( pysb_model: pysb.Model, -) -> Set[str]: +) -> set[str]: """ Computes the set of monomers in a model with species that have fixed initial conditions @@ -988,7 +984,7 @@ def _cl_has_cycle(monomer: str, cl_prototypes: CL_Prototype) -> bool: def _is_in_cycle( - monomer: str, cl_prototypes: CL_Prototype, visited: List[str], root: str + monomer: str, cl_prototypes: CL_Prototype, visited: list[str], root: str ) -> bool: """ Recursively checks for cycles in conservation law dependencies via @@ -1131,7 +1127,7 @@ def _greedy_target_index_update(cl_prototypes: CL_Prototype) -> None: del prototype["appearance_counts"][prototype["local_index"]] -def _get_target_indices(cl_prototypes: CL_Prototype) -> List[List[int]]: +def _get_target_indices(cl_prototypes: CL_Prototype) -> list[list[int]]: """ Computes the list target indices for the current conservation law prototype @@ -1147,7 +1143,7 @@ def _get_target_indices(cl_prototypes: CL_Prototype) -> List[List[int]]: def _construct_conservation_from_prototypes( cl_prototypes: CL_Prototype, pysb_model: pysb.Model -) -> List[ConservationLaw]: +) -> list[ConservationLaw]: """ Computes the algebraic expression for the total amount of a given monomer @@ -1183,7 +1179,7 @@ def _construct_conservation_from_prototypes( def _add_conservation_for_constant_species( - ode_model: DEModel, conservation_laws: List[ConservationLaw] + ode_model: DEModel, conservation_laws: list[ConservationLaw] ) -> None: """ Computes the algebraic expression for the total amount of a given @@ -1209,7 +1205,7 @@ def _add_conservation_for_constant_species( def _flatten_conservation_laws( - conservation_laws: List[ConservationLaw], + conservation_laws: list[ConservationLaw], ) -> None: """ Flatten the conservation laws such that the state_expr not longer @@ -1233,7 +1229,7 @@ def _flatten_conservation_laws( def _apply_conseration_law_sub( - cl: ConservationLaw, sub: Tuple[sp.Symbol, ConservationLaw] + cl: ConservationLaw, sub: tuple[sp.Symbol, ConservationLaw] ) -> bool: """ Applies a substitution to a conservation law by replacing the @@ -1288,8 +1284,8 @@ def _state_in_cl_formula(state: sp.Symbol, cl: ConservationLaw) -> bool: def _get_conservation_law_subs( - conservation_laws: List[ConservationLaw], -) -> List[Tuple[sp.Symbol, Dict[sp.Symbol, sp.Expr]]]: + conservation_laws: list[ConservationLaw], +) -> list[tuple[sp.Symbol, dict[sp.Symbol, sp.Expr]]]: """ Computes a list of (state, coeffs) tuples for conservation laws that still appear in other conservation laws @@ -1353,8 +1349,8 @@ def has_fixed_parameter_ic( def extract_monomers( - complex_patterns: Union[pysb.ComplexPattern, List[pysb.ComplexPattern]], -) -> List[str]: + complex_patterns: Union[pysb.ComplexPattern, list[pysb.ComplexPattern]], +) -> list[str]: """ Constructs a list of monomer names contained in complex patterns. Multiplicity of names corresponds to the stoichiometry in the complex. @@ -1377,7 +1373,7 @@ def extract_monomers( def _get_unconserved_monomers( rule: pysb.Rule, pysb_model: pysb.Model -) -> Set[str]: +) -> set[str]: """ Constructs the set of monomer names for which the specified rule changes the stoichiometry of the monomer in the specified model. @@ -1419,9 +1415,9 @@ def _get_unconserved_monomers( def _get_changed_stoichiometries( - reactants: Union[pysb.ComplexPattern, List[pysb.ComplexPattern]], - products: Union[pysb.ComplexPattern, List[pysb.ComplexPattern]], -) -> Set[str]: + reactants: Union[pysb.ComplexPattern, list[pysb.ComplexPattern]], + products: Union[pysb.ComplexPattern, list[pysb.ComplexPattern]], +) -> set[str]: """ Constructs the set of monomer names which have different stoichiometries in reactants and products. diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index d8361c04ab..8d36ad7b81 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -16,14 +16,10 @@ from typing import ( Any, Callable, - Dict, - Iterable, - List, Optional, - Sequence, - Tuple, Union, ) +from collections.abc import Iterable, Sequence import libsbml as sbml import numpy as np @@ -59,12 +55,12 @@ from .sbml_utils import SBMLException, _parse_logical_operators from .splines import AbstractSpline -SymbolicFormula = Dict[sp.Symbol, sp.Expr] +SymbolicFormula = dict[sp.Symbol, sp.Expr] default_symbols = {symbol: {} for symbol in SymbolId} -ConservationLaw = Dict[str, Union[str, sp.Expr]] +ConservationLaw = dict[str, Union[str, sp.Expr]] logger = get_logger(__name__, logging.ERROR) @@ -176,9 +172,9 @@ def __init__( self.sbml: sbml.Model = self.sbml_doc.getModel() # Long and short names for model components - self.symbols: Dict[SymbolId, Dict[sp.Symbol, Dict[str, Any]]] = {} + self.symbols: dict[SymbolId, dict[sp.Symbol, dict[str, Any]]] = {} - self._local_symbols: Dict[str, Union[sp.Expr, sp.Function]] = {} + self._local_symbols: dict[str, Union[sp.Expr, sp.Function]] = {} self.compartments: SymbolicFormula = {} self.compartment_assignment_rules: SymbolicFormula = {} self.species_assignment_rules: SymbolicFormula = {} @@ -278,13 +274,13 @@ def sbml2amici( self, model_name: str, output_dir: Union[str, Path] = None, - observables: Dict[str, Dict[str, str]] = None, - event_observables: Dict[str, Dict[str, str]] = None, + observables: dict[str, dict[str, str]] = None, + event_observables: dict[str, dict[str, str]] = None, constant_parameters: Iterable[str] = None, - sigmas: Dict[str, Union[str, float]] = None, - event_sigmas: Dict[str, Union[str, float]] = None, - noise_distributions: Dict[str, Union[str, Callable]] = None, - event_noise_distributions: Dict[str, Union[str, Callable]] = None, + sigmas: dict[str, Union[str, float]] = None, + event_sigmas: dict[str, Union[str, float]] = None, + noise_distributions: dict[str, Union[str, Callable]] = None, + event_noise_distributions: dict[str, Union[str, Callable]] = None, verbose: Union[int, bool] = logging.ERROR, assume_pow_positivity: bool = False, compiler: str = None, @@ -456,13 +452,13 @@ def sbml2amici( def _build_ode_model( self, - observables: Dict[str, Dict[str, str]] = None, - event_observables: Dict[str, Dict[str, str]] = None, + observables: dict[str, dict[str, str]] = None, + event_observables: dict[str, dict[str, str]] = None, constant_parameters: Iterable[str] = None, - sigmas: Dict[str, Union[str, float]] = None, - event_sigmas: Dict[str, Union[str, float]] = None, - noise_distributions: Dict[str, Union[str, Callable]] = None, - event_noise_distributions: Dict[str, Union[str, Callable]] = None, + sigmas: dict[str, Union[str, float]] = None, + event_sigmas: dict[str, Union[str, float]] = None, + noise_distributions: dict[str, Union[str, Callable]] = None, + event_noise_distributions: dict[str, Union[str, Callable]] = None, verbose: Union[int, bool] = logging.ERROR, compute_conservation_laws: bool = True, simplify: Optional[Callable] = _default_simplify, @@ -546,7 +542,7 @@ def _build_ode_model( @log_execution_time("importing SBML", logger) def _process_sbml( self, - constant_parameters: List[str] = None, + constant_parameters: list[str] = None, hardcode_symbols: Sequence[str] = None, ) -> None: """ @@ -1034,7 +1030,7 @@ def _process_annotations(self) -> None: @log_execution_time("processing SBML parameters", logger) def _process_parameters( self, - constant_parameters: List[str] = None, + constant_parameters: list[str] = None, hardcode_symbols: Sequence[str] = None, ) -> None: """ @@ -1604,9 +1600,9 @@ def get_empty_bolus_value() -> sp.Float: @log_execution_time("processing SBML observables", logger) def _process_observables( self, - observables: Union[Dict[str, Dict[str, str]], None], - sigmas: Dict[str, Union[str, float]], - noise_distributions: Dict[str, str], + observables: Union[dict[str, dict[str, str]], None], + sigmas: dict[str, Union[str, float]], + noise_distributions: dict[str, str], ) -> None: """ Perform symbolic computations required for observable and objective @@ -1670,9 +1666,9 @@ def _process_observables( @log_execution_time("processing SBML event observables", logger) def _process_event_observables( self, - event_observables: Dict[str, Dict[str, str]], - event_sigmas: Dict[str, Union[str, float]], - event_noise_distributions: Dict[str, str], + event_observables: dict[str, dict[str, str]], + event_sigmas: dict[str, Union[str, float]], + event_noise_distributions: dict[str, str], ) -> None: """ Perform symbolic computations required for observable and objective @@ -1787,8 +1783,8 @@ def _generate_default_observables(self): def _process_log_likelihood( self, - sigmas: Dict[str, Union[str, float]], - noise_distributions: Dict[str, str], + sigmas: dict[str, Union[str, float]], + noise_distributions: dict[str, str], events: bool = False, event_reg: bool = False, ): @@ -2016,7 +2012,7 @@ def process_conservation_laws(self, ode_model) -> None: def _get_conservation_laws_demartino( self, ode_model: DEModel, - ) -> List[Tuple[int, List[int], List[float]]]: + ) -> list[tuple[int, list[int], list[float]]]: """Identify conservation laws based on algorithm by DeMartino et al. (see conserved_moieties.py). @@ -2092,7 +2088,7 @@ def _get_conservation_laws_demartino( def _get_conservation_laws_rref( self, - ) -> List[Tuple[int, List[int], List[float]]]: + ) -> list[tuple[int, list[int], list[float]]]: """Identify conservation laws based on left nullspace of the stoichiometric matrix, computed through (numeric) Gaussian elimination @@ -2155,8 +2151,8 @@ def _get_conservation_laws_rref( return raw_cls def _add_conservation_for_non_constant_species( - self, model: DEModel, conservation_laws: List[ConservationLaw] - ) -> List[int]: + self, model: DEModel, conservation_laws: list[ConservationLaw] + ) -> list[int]: """Add non-constant species to conservation laws :param model: @@ -2639,8 +2635,8 @@ def assignmentRules2observables( def _add_conservation_for_constant_species( - ode_model: DEModel, conservation_laws: List[ConservationLaw] -) -> List[int]: + ode_model: DEModel, conservation_laws: list[ConservationLaw] +) -> list[int]: """ Adds constant species to conservations laws @@ -2737,7 +2733,7 @@ def get_species_initial(species: sbml.Species) -> sp.Expr: def _get_list_of_species_references( sbml_model: sbml.Model, -) -> List[sbml.SpeciesReference]: +) -> list[sbml.SpeciesReference]: """ Extracts list of species references as SBML doesn't provide a native function for this. @@ -2812,9 +2808,9 @@ def _parse_special_functions_sbml( def _validate_observables( - observables: Union[Dict[str, Dict[str, str]], None], - sigmas: Dict[str, Union[str, float]], - noise_distributions: Dict[str, str], + observables: Union[dict[str, dict[str, str]], None], + sigmas: dict[str, Union[str, float]], + noise_distributions: dict[str, str], events: bool = False, ) -> None: if observables is None or not observables: @@ -2842,7 +2838,7 @@ def _validate_observables( def _check_symbol_nesting( - symbols: Dict[sp.Symbol, Dict[str, sp.Expr]], symbol_type: str + symbols: dict[sp.Symbol, dict[str, sp.Expr]], symbol_type: str ): observable_syms = set(symbols.keys()) for obs in symbols.values(): diff --git a/python/sdist/amici/sbml_utils.py b/python/sdist/amici/sbml_utils.py index 75bcb82a18..d40610f4ab 100644 --- a/python/sdist/amici/sbml_utils.py +++ b/python/sdist/amici/sbml_utils.py @@ -11,7 +11,7 @@ import sympy as sp if TYPE_CHECKING: - from typing import Any, Dict, Optional, Tuple, Union + from typing import Any, Union SbmlID = Union[str, sp.Symbol] @@ -52,7 +52,7 @@ class SbmlAnnotationError(SBMLException): def create_sbml_model( model_id: str, level: int = 2, version: int = 5 -) -> Tuple[libsbml.SBMLDocument, libsbml.Model]: +) -> tuple[libsbml.SBMLDocument, libsbml.Model]: """Helper for creating an empty SBML model. :param model_id: @@ -116,10 +116,10 @@ def add_species( model: libsbml.Model, species_id: SbmlID, *, - compartment_id: Optional[str] = None, - name: Union[bool, str] = False, + compartment_id: str | None = None, + name: bool | str = False, initial_amount: float = 0.0, - units: Optional[str] = None, + units: str | None = None, ) -> libsbml.Species: """Helper for adding a species to a SBML model. @@ -182,10 +182,10 @@ def add_parameter( model: libsbml.Model, parameter_id: SbmlID, *, - name: Union[bool, str] = False, - value: Optional[float] = None, - units: Optional[str] = None, - constant: Optional[bool] = None, + name: bool | str = False, + value: float | None = None, + units: str | None = None, + constant: bool | None = None, ) -> libsbml.Parameter: """Helper for adding a parameter to a SBML model. @@ -239,7 +239,7 @@ def add_assignment_rule( model: libsbml.Model, variable_id: SbmlID, formula, - rule_id: Optional[str] = None, + rule_id: str | None = None, ) -> libsbml.AssignmentRule: """Helper for adding an assignment rule to a SBML model. @@ -287,7 +287,7 @@ def add_rate_rule( model: libsbml.Model, variable_id: SbmlID, formula, - rule_id: Optional[str] = None, + rule_id: str | None = None, ) -> libsbml.RateRule: """ Helper for adding a rate rule to a SBML model. @@ -337,7 +337,7 @@ def add_inflow( species_id: SbmlID, rate, *, - reaction_id: Optional[str] = None, + reaction_id: str | None = None, reversible: bool = False, ) -> libsbml.Reaction: species_id = str(species_id) @@ -364,9 +364,7 @@ def add_inflow( return reaction -def get_sbml_units( - model: libsbml.Model, x: Union[SbmlID, sp.Basic] -) -> Union[None, str]: +def get_sbml_units(model: libsbml.Model, x: SbmlID | sp.Basic) -> None | str: """Try to get the units for expression `x`. :param model: @@ -493,7 +491,7 @@ def mathml2sympy( mathml: str, *, evaluate: bool = False, - locals: Optional[Dict[str, Any]] = None, + locals: dict[str, Any] | None = None, expression_type: str = "mathml2sympy", ) -> sp.Basic: ast = libsbml.readMathMLFromString(mathml) @@ -519,8 +517,8 @@ def mathml2sympy( def _parse_logical_operators( - math_str: Union[str, float, None], -) -> Union[str, float, None]: + math_str: str | float | None, +) -> str | float | None: """ Parses a math string in order to replace logical operators by a form parsable for sympy diff --git a/python/sdist/amici/splines.py b/python/sdist/amici/splines.py index 657170c2f5..d55a78137b 100644 --- a/python/sdist/amici/splines.py +++ b/python/sdist/amici/splines.py @@ -14,20 +14,15 @@ from typing import ( Any, Callable, - Dict, - List, - Optional, - Sequence, - Set, - Tuple, Union, ) + from collections.abc import Sequence from . import sbml_import - BClike = Union[None, str, Tuple[Union[None, str], Union[None, str]]] + BClike = Union[None, str, tuple[Union[None, str], Union[None, str]]] - NormalizedBC = Tuple[Union[None, str], Union[None, str]] + NormalizedBC = tuple[Union[None, str], Union[None, str]] import collections.abc import logging @@ -88,11 +83,11 @@ class UniformGrid(collections.abc.Sequence): def __init__( self, - start: Union[Real, sp.Basic], - stop: Union[Real, sp.Basic], - step: Optional[Union[Real, sp.Basic]] = None, + start: Real | sp.Basic, + stop: Real | sp.Basic, + step: Real | sp.Basic | None = None, *, - number_of_nodes: Optional[Integral] = None, + number_of_nodes: Integral | None = None, always_include_stop: bool = True, ): """Create a new ``UniformGrid``. @@ -219,11 +214,11 @@ class AbstractSpline(ABC): def __init__( self, - sbml_id: Union[str, sp.Symbol], + sbml_id: str | sp.Symbol, nodes: Sequence, values_at_nodes: Sequence, *, - evaluate_at: Optional[Union[str, sp.Basic]] = None, + evaluate_at: str | sp.Basic | None = None, bc: BClike = None, extrapolate: BClike = None, logarithmic_parametrization: bool = False, @@ -418,7 +413,7 @@ def _normalize_bc(bc: BClike) -> NormalizedBC: def _normalize_extrapolate( self, bc: NormalizedBC, extrapolate: BClike - ) -> Tuple[NormalizedBC, NormalizedBC]: + ) -> tuple[NormalizedBC, NormalizedBC]: """ Preprocess `extrapolate` to a standard form and perform consistency checks @@ -576,10 +571,10 @@ def check_if_valid(self, importer: sbml_import.SbmlImporter) -> None: # until (if at all) they are accounted for. from .de_export import SymbolId - fixed_parameters: List[sp.Symbol] = list( + fixed_parameters: list[sp.Symbol] = list( importer.symbols[SymbolId.FIXED_PARAMETER].keys() ) - species: List[sp.Symbol] = list( + species: list[sp.Symbol] = list( importer.symbols[SymbolId.SPECIES].keys() ) @@ -606,9 +601,7 @@ def check_if_valid(self, importer: sbml_import.SbmlImporter) -> None: if not np.all(np.diff(nodes_values) >= 0): raise ValueError("nodes should be strictly increasing!") - def poly( - self, i: Integral, *, x: Union[Real, sp.Basic] = None - ) -> sp.Basic: + def poly(self, i: Integral, *, x: Real | sp.Basic = None) -> sp.Basic: """ Get the polynomial interpolant on the ``(nodes[i], nodes[i+1])`` interval. The polynomial is written in Horner form with respect to the scaled @@ -646,7 +639,7 @@ def poly( with evaluate(False): return poly.subs(t, t_value) - def poly_variable(self, x: Union[Real, sp.Basic], i: Integral) -> sp.Basic: + def poly_variable(self, x: Real | sp.Basic, i: Integral) -> sp.Basic: """ Given an evaluation point, return the value of the variable in which the polynomial on the ``i``-th interval is expressed. @@ -656,15 +649,13 @@ def poly_variable(self, x: Union[Real, sp.Basic], i: Integral) -> sp.Basic: return self._poly_variable(x, i) @abstractmethod - def _poly_variable( - self, x: Union[Real, sp.Basic], i: Integral - ) -> sp.Basic: + def _poly_variable(self, x: Real | sp.Basic, i: Integral) -> sp.Basic: """This function (and not poly_variable) should be implemented by the subclasses""" raise NotImplementedError() @abstractmethod - def _poly(self, t: Union[Real, sp.Basic], i: Integral) -> sp.Basic: + def _poly(self, t: Real | sp.Basic, i: Integral) -> sp.Basic: """ Return the symbolic expression for the spline restricted to the `i`-th interval as a polynomial in the scaled variable `t`. @@ -672,7 +663,7 @@ def _poly(self, t: Union[Real, sp.Basic], i: Integral) -> sp.Basic: raise NotImplementedError() def segment_formula( - self, i: Integral, *, x: Union[Real, sp.Basic] = None + self, i: Integral, *, x: Real | sp.Basic = None ) -> sp.Basic: """ Return the formula for the actual value of the spline expression @@ -700,7 +691,7 @@ def y_scaled(self, i: Integral): @property def extrapolation_formulas( self, - ) -> Tuple[Union[None, sp.Basic], Union[None, sp.Basic]]: + ) -> tuple[None | sp.Basic, None | sp.Basic]: """ Returns the extrapolation formulas on the left and right side of the interval ``(nodes[0], nodes[-1])``. @@ -710,9 +701,9 @@ def extrapolation_formulas( def _extrapolation_formulas( self, - x: Union[Real, sp.Basic], - extrapolate: Optional[NormalizedBC] = None, - ) -> Tuple[Union[None, sp.Expr], Union[None, sp.Expr]]: + x: Real | sp.Basic, + extrapolate: NormalizedBC | None = None, + ) -> tuple[None | sp.Expr, None | sp.Expr]: if extrapolate is None: extr_left, extr_right = self.extrapolate else: @@ -770,7 +761,7 @@ def mathml_formula(self) -> sp.Piecewise: def _formula( self, *, - x: Union[Real, sp.Basic] = None, + x: Real | sp.Basic = None, sbml_syms: bool = False, sbml_ops: bool = False, cache: bool = True, @@ -845,15 +836,15 @@ def _formula( return formula @property - def period(self) -> Union[sp.Basic, None]: + def period(self) -> sp.Basic | None: """Period of a periodic spline. `None` if the spline is not periodic.""" if self.bc == ("periodic", "periodic"): return self.nodes[-1] - self.nodes[0] return None def _to_base_interval( - self, x: Union[Real, sp.Basic], *, with_interval_number: bool = False - ) -> Union[sp.Basic, Tuple[sp.core.numbers.Integer, sp.Basic]]: + self, x: Real | sp.Basic, *, with_interval_number: bool = False + ) -> sp.Basic | tuple[sp.core.numbers.Integer, sp.Basic]: """For periodic splines, maps the real point `x` to the reference period.""" if self.bc != ("periodic", "periodic"): @@ -874,19 +865,19 @@ def _to_base_interval( return k, z return z - def evaluate(self, x: Union[Real, sp.Basic]) -> sp.Basic: + def evaluate(self, x: Real | sp.Basic) -> sp.Basic: """Evaluate the spline at the point `x`.""" _x = sp.Dummy("x") return self._formula(x=_x, cache=False).subs(_x, x) - def derivative(self, x: Union[Real, sp.Basic], **kwargs) -> sp.Expr: + def derivative(self, x: Real | sp.Basic, **kwargs) -> sp.Expr: """Evaluate the spline derivative at the point `x`.""" # NB kwargs are used to pass on extrapolate=None # when called from .extrapolation_formulas() _x = sp.Dummy("x") return self._formula(x=_x, cache=False, **kwargs).diff(_x).subs(_x, x) - def second_derivative(self, x: Union[Real, sp.Basic]) -> sp.Basic: + def second_derivative(self, x: Real | sp.Basic) -> sp.Basic: """Evaluate the spline second derivative at the point `x`.""" _x = sp.Dummy("x") return self._formula(x=_x, cache=False).diff(_x).diff(_x).subs(_x, x) @@ -907,9 +898,7 @@ def squared_L2_norm_of_curvature(self) -> sp.Basic: ) return sp.simplify(integral) - def integrate( - self, x0: Union[Real, sp.Basic], x1: Union[Real, sp.Basic] - ) -> sp.Basic: + def integrate(self, x0: Real | sp.Basic, x1: Real | sp.Basic) -> sp.Basic: """Integrate the spline between the points `x0` and `x1`.""" x = sp.Dummy("x") x0, x1 = sp.sympify((x0, x1)) @@ -969,7 +958,7 @@ def amici_annotation(self) -> str: # Check XML and prettify return pretty_xml(annotation) - def _annotation_attributes(self) -> Dict[str, Any]: + def _annotation_attributes(self) -> dict[str, Any]: attributes = {"spline_method": self.method} if self.bc[0] == self.bc[1]: @@ -996,7 +985,7 @@ def _annotation_attributes(self) -> Dict[str, Any]: return attributes - def _annotation_children(self) -> Dict[str, Union[str, List[str]]]: + def _annotation_children(self) -> dict[str, str | list[str]]: children = {} with evaluate(False): @@ -1024,12 +1013,12 @@ def add_to_sbml_model( self, model: libsbml.Model, *, - auto_add: Union[bool, str] = False, - x_nominal: Optional[Sequence[float]] = None, - y_nominal: Optional[Union[Sequence[float], float]] = None, - x_units: Optional[str] = None, - y_units: Optional[str] = None, - y_constant: Optional[Union[Sequence[bool], bool]] = None, + auto_add: bool | str = False, + x_nominal: Sequence[float] | None = None, + y_nominal: Sequence[float] | float | None = None, + x_units: str | None = None, + y_units: str | None = None, + y_constant: Sequence[bool] | bool | None = None, ) -> None: """ Function to add the spline to an SBML model using an assignment rule @@ -1196,7 +1185,7 @@ def is_spline(rule: libsbml.AssignmentRule) -> bool: @staticmethod def get_annotation( rule: libsbml.AssignmentRule, - ) -> Union[ET.Element, None]: + ) -> ET.Element | None: """ Extract AMICI spline annotation from an SBML assignment rule (given as a :py:class:`libsbml.AssignmentRule` object). @@ -1216,7 +1205,7 @@ def from_annotation( sbml_id: sp.Symbol, annotation: ET.Element, *, - locals_: Dict[str, Any], + locals_: dict[str, Any], ) -> AbstractSpline: """Create a spline object from a SBML annotation. @@ -1289,9 +1278,9 @@ def from_annotation( @classmethod def _from_annotation( cls, - attributes: Dict[str, Any], - children: Dict[str, List[sp.Basic]], - ) -> Dict[str, Any]: + attributes: dict[str, Any], + children: dict[str, list[sp.Basic]], + ) -> dict[str, Any]: """ Given the attributes and children of a AMICI spline annotation, returns the keyword arguments to be passed @@ -1354,7 +1343,7 @@ def _from_annotation( return kwargs - def parameters(self, importer: sbml_import.SbmlImporter) -> Set[sp.Symbol]: + def parameters(self, importer: sbml_import.SbmlImporter) -> set[sp.Symbol]: """Returns the SBML parameters used by this spline""" from .de_export import SymbolId @@ -1362,7 +1351,7 @@ def parameters(self, importer: sbml_import.SbmlImporter) -> Set[sp.Symbol]: set(importer.symbols[SymbolId.PARAMETER].keys()) ) - def _parameters(self) -> Set[sp.Symbol]: + def _parameters(self) -> set[sp.Symbol]: parameters = set() for y in self.values_at_nodes: parameters.update(y.free_symbols) @@ -1451,12 +1440,12 @@ def _eval_is_real(self): def plot( self, - parameters: Optional[Dict] = None, + parameters: dict | None = None, *, - xlim: Optional[Tuple[float, float]] = None, + xlim: tuple[float, float] | None = None, npoints: int = 100, - xlabel: Optional[str] = None, - ylabel: Union[str, None] = "spline value", + xlabel: str | None = None, + ylabel: str | None = "spline value", ax=None, ): "Plots the spline, highlighting the nodes positions." @@ -1486,9 +1475,9 @@ def plot( def spline_user_functions( - splines: List[AbstractSpline], - p_index: Dict[sp.Symbol, int], -) -> Dict[str, List[Tuple[Callable[..., bool], Callable[..., str]]]]: + splines: list[AbstractSpline], + p_index: dict[sp.Symbol, int], +) -> dict[str, list[tuple[Callable[..., bool], Callable[..., str]]]]: """ Custom user functions to be used in `ODEExporter` for linking spline expressions to C++ code. @@ -1522,12 +1511,12 @@ def spline_user_functions( class CubicHermiteSpline(AbstractSpline): def __init__( self, - sbml_id: Union[str, sp.Symbol], + sbml_id: str | sp.Symbol, nodes: Sequence, values_at_nodes: Sequence, derivatives_at_nodes: Sequence = None, *, - evaluate_at: Optional[Union[str, sp.Basic]] = None, + evaluate_at: str | sp.Basic | None = None, bc: BClike = "auto", extrapolate: BClike = None, logarithmic_parametrization: bool = False, @@ -1672,7 +1661,7 @@ def check_if_valid(self, importer: sbml_import.SbmlImporter) -> None: # TODO this is very much a draft from .de_export import SymbolId - species: List[sp.Symbol] = list(importer.symbols[SymbolId.SPECIES]) + species: list[sp.Symbol] = list(importer.symbols[SymbolId.SPECIES]) for d in self.derivatives_at_nodes: if len(d.free_symbols.intersection(species)) != 0: raise ValueError( @@ -1691,15 +1680,13 @@ def d_scaled(self, i: Integral) -> sp.Expr: return self.derivatives_at_nodes[i] / self.values_at_nodes[i] return self.derivatives_at_nodes[i] - def _poly_variable( - self, x: Union[Real, sp.Basic], i: Integral - ) -> sp.Basic: + def _poly_variable(self, x: Real | sp.Basic, i: Integral) -> sp.Basic: assert 0 <= i < len(self.nodes) - 1 dx = self.nodes[i + 1] - self.nodes[i] with evaluate(False): return (x - self.nodes[i]) / dx - def _poly(self, t: Union[Real, sp.Basic], i: Integral) -> sp.Basic: + def _poly(self, t: Real | sp.Basic, i: Integral) -> sp.Basic: """ Return the symbolic expression for the spline restricted to the `i`-th interval as polynomial in the scaled variable `t`. @@ -1721,7 +1708,7 @@ def _poly(self, t: Union[Real, sp.Basic], i: Integral) -> sp.Basic: with evaluate(False): return h00 * y0 + h10 * dx * dy0 + h01 * y1 + h11 * dx * dy1 - def _annotation_children(self) -> Dict[str, Union[str, List[str]]]: + def _annotation_children(self) -> dict[str, str | list[str]]: children = super()._annotation_children() if not self._derivatives_by_fd: children["spline_derivatives"] = [ @@ -1729,7 +1716,7 @@ def _annotation_children(self) -> Dict[str, Union[str, List[str]]]: ] return children - def _parameters(self) -> Set[sp.Symbol]: + def _parameters(self) -> set[sp.Symbol]: parameters = super()._parameters() for d in self.derivatives_at_nodes: parameters.update(d.free_symbols) @@ -1744,7 +1731,7 @@ def _replace_in_all_expressions( ] @classmethod - def _from_annotation(cls, attributes, children) -> Dict[str, Any]: + def _from_annotation(cls, attributes, children) -> dict[str, Any]: kwargs = super()._from_annotation(attributes, children) if "spline_derivatives" in children.keys(): diff --git a/python/sdist/amici/swig.py b/python/sdist/amici/swig.py index ea7ad1f3a1..902145ff3e 100644 --- a/python/sdist/amici/swig.py +++ b/python/sdist/amici/swig.py @@ -111,7 +111,7 @@ def fix_typehints(infilename, outfilename): return # file -> AST - with open(infilename, "r") as f: + with open(infilename) as f: source = f.read() parsed_source = ast.parse(source) diff --git a/python/sdist/amici/swig_wrappers.py b/python/sdist/amici/swig_wrappers.py index 4983a28f23..e16d4c2580 100644 --- a/python/sdist/amici/swig_wrappers.py +++ b/python/sdist/amici/swig_wrappers.py @@ -3,7 +3,8 @@ import sys import warnings from contextlib import contextmanager, suppress -from typing import Any, Dict, List, Optional, Sequence, Union +from typing import Any, Optional, Union +from collections.abc import Sequence import amici import amici.amici as amici_swig @@ -154,7 +155,7 @@ def runAmiciSimulations( edata_list: AmiciExpDataVector, failfast: bool = True, num_threads: int = 1, -) -> List["numpy.ReturnDataView"]: +) -> list["numpy.ReturnDataView"]: """ Convenience wrapper for loops of amici.runAmiciSimulation @@ -254,7 +255,7 @@ def writeSolverSettingsToHDF5( def get_model_settings( model: AmiciModel, -) -> Dict[str, Any]: +) -> dict[str, Any]: """Get model settings that are set independently of the compiled model. :param model: The AMICI model instance. @@ -285,7 +286,7 @@ def get_model_settings( def set_model_settings( model: AmiciModel, - settings: Dict[str, Any], + settings: dict[str, Any], ) -> None: """Set model settings. diff --git a/python/sdist/setup.py b/python/sdist/setup.py index 4d65634cc2..ed65127f7a 100755 --- a/python/sdist/setup.py +++ b/python/sdist/setup.py @@ -146,7 +146,6 @@ def main(): # (https://pypi.org/project/amici/) with open( os.path.join(os.path.dirname(__file__), "README.md"), - "r", encoding="utf-8", ) as fh: long_description = fh.read() diff --git a/python/tests/pysb_test_models/bngwiki_egfr_simple_deletemolecules.py b/python/tests/pysb_test_models/bngwiki_egfr_simple_deletemolecules.py index 767c239c5d..1a39d4a846 100644 --- a/python/tests/pysb_test_models/bngwiki_egfr_simple_deletemolecules.py +++ b/python/tests/pysb_test_models/bngwiki_egfr_simple_deletemolecules.py @@ -3,7 +3,6 @@ http://bionetgen.org/index.php/Egfr_simple """ -from __future__ import print_function from pysb import * diff --git a/python/tests/splines_utils.py b/python/tests/splines_utils.py index f50b71c6eb..29024d3b73 100644 --- a/python/tests/splines_utils.py +++ b/python/tests/splines_utils.py @@ -8,7 +8,8 @@ import os import uuid from tempfile import mkdtemp -from typing import Any, Dict, List, Optional, Sequence, Union +from typing import Any, Optional, Union +from collections.abc import Sequence import amici import numpy as np @@ -44,7 +45,7 @@ def evaluate_spline( def integrate_spline( spline: AbstractSpline, - params: Union[Dict, None], + params: Union[dict, None], tt: Sequence[float], initial_value: float = 0, ): @@ -116,8 +117,8 @@ def species_to_index(name) -> int: def create_petab_problem( - splines: List[AbstractSpline], - params_true: Dict, + splines: list[AbstractSpline], + params_true: dict, initial_values: Optional[np.ndarray] = None, use_reactions: bool = False, measure_upsample: int = 6, @@ -514,7 +515,7 @@ def check_splines( w_atol: float = 1e-11, sx_rtol: float = 1e-10, sx_atol: float = 1e-10, - groundtruth: Optional[Union[str, Dict[str, Any]]] = None, + groundtruth: Optional[Union[str, dict[str, Any]]] = None, **kwargs, ): """ diff --git a/python/tests/test_misc.py b/python/tests/test_misc.py index 5a88fda6f8..24bba79888 100644 --- a/python/tests/test_misc.py +++ b/python/tests/test_misc.py @@ -78,8 +78,7 @@ def test_cmake_compilation(sbml_example_presimulation_module): cmd, shell=True, check=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, ) except subprocess.CalledProcessError as e: print(e.stdout.decode()) diff --git a/tests/conftest.py b/tests/conftest.py index 7d98a09abb..9b7dd7fb08 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ import re import sys from pathlib import Path -from typing import TYPE_CHECKING, List, Set, Tuple +from typing import TYPE_CHECKING import pytest @@ -24,7 +24,7 @@ def sbml_semantic_cases_dir() -> Path: return SBML_SEMANTIC_CASES_DIR -def parse_selection(selection_str: str, last: int) -> List[int]: +def parse_selection(selection_str: str, last: int) -> list[int]: """ Parse comma-separated list of integer ranges, return selected indices as integer list @@ -131,7 +131,7 @@ def pytest_runtest_logreport(report: "TestReport") -> None: passed_ids.append(test_case_id) -def get_tags_for_test(test_id: str) -> Tuple[Set[str], Set[str]]: +def get_tags_for_test(test_id: str) -> tuple[set[str], set[str]]: """Get sbml test suite tags for the given test ID Returns: diff --git a/tests/petab_test_suite/conftest.py b/tests/petab_test_suite/conftest.py index df0b00ee86..2e1c6d3cea 100644 --- a/tests/petab_test_suite/conftest.py +++ b/tests/petab_test_suite/conftest.py @@ -2,12 +2,11 @@ import re import sys -from typing import List from petabtests.core import get_cases -def parse_selection(selection_str: str) -> List[int]: +def parse_selection(selection_str: str) -> list[int]: """ Parse comma-separated list of integer ranges, return selected indices as integer list