diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 974a8f5..735df31 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -41,7 +41,6 @@ repos: - --fix - --config - pyproject.toml - # Run the formatter. - id: ruff-format args: diff --git a/fiddy/analysis.py b/fiddy/analysis.py index dd0f549..7fefad8 100644 --- a/fiddy/analysis.py +++ b/fiddy/analysis.py @@ -1,6 +1,6 @@ import abc from dataclasses import dataclass, field -from typing import Any, Dict +from typing import Any import numpy as np @@ -12,7 +12,7 @@ class AnalysisResult: method_id: str value: Any - metadata: Dict[str, Any] = field(default_factory=dict) + metadata: dict[str, Any] = field(default_factory=dict) class Analysis: @@ -93,7 +93,7 @@ class TransformByDirectionScale(Analysis): LOG_E_10 = np.log(10) only_at_completion: bool = True - def __init__(self, scales: Dict[str, str]): + def __init__(self, scales: dict[str, str]): self.scales = scales super().__init__() diff --git a/fiddy/constants.py b/fiddy/constants.py index 9b85779..7b3e535 100644 --- a/fiddy/constants.py +++ b/fiddy/constants.py @@ -1,5 +1,6 @@ +from collections.abc import Callable from enum import Enum -from typing import Any, Callable, Union +from typing import Any, Union import numpy as np from numpy.typing import NDArray @@ -32,7 +33,7 @@ class Type: # - "ANALYSE_DIRECTIONAL_DERIVATIVE_METHOD" and # - "ANALYSE_DERIVATIVE_METHOD" and ANALYSIS_METHOD = Callable[["DirectionalDerivative"], Any] # noqa: F821 - SUCCESS_CHECKER = Callable[["Derivative"], Union[bool, Any]] # noqa: F821 + SUCCESS_CHECKER = Callable[["Derivative"], bool | Any] # noqa: F821 # FIXME rename, since this can be the name of the base class in `derivative.py` diff --git a/fiddy/derivative.py b/fiddy/derivative.py index 65508ac..48e69d2 100644 --- a/fiddy/derivative.py +++ b/fiddy/derivative.py @@ -1,4 +1,4 @@ -from typing import Callable, Dict, List, Union +from collections.abc import Callable import numpy as np import pandas as pd @@ -59,7 +59,7 @@ class Derivative: def __init__( self, # function: TYPE_FUNCTION, - directional_derivatives: List[DirectionalDerivative], + directional_derivatives: list[DirectionalDerivative], autorun: bool = True, # custom_methods: Dict[str, TYPE_FUNCTION] = None, ): @@ -124,21 +124,21 @@ def get_derivative( point: Type.POINT, # TODO store these defaults in some dictionary that a user can easily modify # TODO Default to some list e.g. [1e-3, 1e-5] - sizes: List[Type.SIZE], + sizes: list[Type.SIZE], # TODO Default to e.g. ["forward", "backward", "central"] - method_ids: List[Union[str, MethodId]], + method_ids: list[str | MethodId], # TODO for gradient check; add support for methods # TODO add some default consistency check # TODO change to class that can be initialized with.. directional_derivative object? success_checker: Success, *args, - analysis_classes: List[Analysis] = None, + analysis_classes: list[Analysis] = None, relative_sizes: bool = False, - directions: Union[List[Type.DIRECTION], Dict[str, Type.DIRECTION]] = None, - direction_ids: List[str] = None, - direction_indices: List[int] = None, - custom_methods: Dict[str, Callable] = None, - expected_result: List[Type.SCALAR] = None, + directions: list[Type.DIRECTION] | dict[str, Type.DIRECTION] = None, + direction_ids: list[str] = None, + direction_indices: list[int] = None, + custom_methods: dict[str, Callable] = None, + expected_result: list[Type.SCALAR] = None, **kwargs, ): """Get a derivative. @@ -171,7 +171,7 @@ def get_derivative( if analysis_classes is None: analysis_classes = [] directional_derivatives = [] - for direction_id, direction in zip(direction_ids, directions): + for direction_id, direction in zip(direction_ids, directions, strict=True): computers = [] for size in sizes: for method_id in method_ids: diff --git a/fiddy/derivative_check.py b/fiddy/derivative_check.py index ac3be92..7f96d59 100644 --- a/fiddy/derivative_check.py +++ b/fiddy/derivative_check.py @@ -1,6 +1,6 @@ import abc from dataclasses import dataclass -from typing import Any, Dict, List +from typing import Any import numpy as np import pandas as pd @@ -21,7 +21,7 @@ class DirectionalDerivativeCheckResult: """The expected value.""" success: bool """Whether the check passed.""" - output: Dict[str, Any] = None + output: dict[str, Any] = None """Miscellaneous output from the method.""" @@ -29,7 +29,7 @@ class DirectionalDerivativeCheckResult: class DerivativeCheckResult: method_id: str """The method that determined whether the directional derivative is correct.""" - directional_derivative_check_results: List[ + directional_derivative_check_results: list[ DirectionalDerivativeCheckResult ] """The results from checking individual directions.""" @@ -39,7 +39,7 @@ class DerivativeCheckResult: """The expected value.""" success: bool """Whether the check passed.""" - output: Dict[str, Any] = None + output: dict[str, Any] = None """Miscellaneous output from the method.""" @property diff --git a/fiddy/directional_derivative.py b/fiddy/directional_derivative.py index 9f9c168..f225029 100644 --- a/fiddy/directional_derivative.py +++ b/fiddy/directional_derivative.py @@ -1,7 +1,8 @@ import abc import warnings +from collections.abc import Callable from dataclasses import dataclass, field -from typing import Any, Callable, Dict, List, Tuple, Union +from typing import Any import numpy as np @@ -14,7 +15,7 @@ class ComputerResult: method_id: str value: Type.DIRECTIONAL_DERIVATIVE - metadata: Dict[str, Any] = field(default_factory=dict) + metadata: dict[str, Any] = field(default_factory=dict) @dataclass @@ -26,11 +27,11 @@ class Computer: # FIXME support callable size: Type.SIZE # Change to callable? - method: Union[Type.DIRECTIONAL_DERIVATIVE_FUNCTION, MethodId] + method: Type.DIRECTIONAL_DERIVATIVE_FUNCTION | MethodId function: Type.FUNCTION autorun: bool = True completed: bool = False - results: List[ComputerResult] = field(default_factory=list) + results: list[ComputerResult] = field(default_factory=list) # value: Type.DIRECTIONAL_DERIVATIVE = None relative_size: bool = False @@ -130,10 +131,10 @@ class DirectionalDerivative: id: str direction: Type.DIRECTION # FIXME rename to just computers - pending_computers: List[Computer] - computers: List[Computer] + pending_computers: list[Computer] + computers: list[Computer] # TODO change to `analysis.Analysis` instead of `Type.ANALYSIS_METHOD` - analyses: List[Type.ANALYSIS_METHOD] + analyses: list[Type.ANALYSIS_METHOD] # A method that acts on the information in the direction result, # including gradient approximation values and post-processing results, # to determine whether the gradient was computed successfully. @@ -266,7 +267,7 @@ def __call__( ) @abc.abstractmethod - def compute(self, points: List[Type.POINT]): + def compute(self, points: list[Type.POINT]): """Compute the directional derivative. Args: @@ -281,7 +282,7 @@ def compute(self, points: List[Type.POINT]): class TwoPointSlopeDirectionalDirection(DirectionalDerivativeBase): """Derivatives that are similar to a simple `(y1-y0)/h` slope function.""" - def compute(self, points: List[Type.POINT], size: Type.SIZE, **kwargs): + def compute(self, points: list[Type.POINT], size: Type.SIZE, **kwargs): y0, y1 = self.function(points[0]), self.function(points[1]) return (y1 - y0) / size @@ -410,7 +411,7 @@ def compute( } -def standard_basis(point: Type.POINT) -> List[Type.DIRECTION]: +def standard_basis(point: Type.POINT) -> list[Type.DIRECTION]: """Get standard basis (Cartesian/one-hot) vectors. Args: @@ -425,10 +426,10 @@ def standard_basis(point: Type.POINT) -> List[Type.DIRECTION]: def get_directions( point: Type.POINT = None, - directions: Union[List[Type.DIRECTION], Dict[str, Type.DIRECTION]] = None, - ids: List[str] = None, - indices: List[int] = None, -) -> Tuple[str, Type.DIRECTION]: + directions: list[Type.DIRECTION] | dict[str, Type.DIRECTION] = None, + ids: list[str] = None, + indices: list[int] = None, +) -> tuple[str, Type.DIRECTION]: """Get directions from minimal information. Args: diff --git a/fiddy/extensions/amici/amici.py b/fiddy/extensions/amici/amici.py index 0ff6192..e37f81d 100644 --- a/fiddy/extensions/amici/amici.py +++ b/fiddy/extensions/amici/amici.py @@ -1,6 +1,7 @@ +from collections.abc import Callable from functools import partial from inspect import signature -from typing import Any, Callable, Dict, List, Tuple +from typing import Any import amici import amici.petab.simulations @@ -68,14 +69,14 @@ def transform_gradient_lin_to_log10(gradient_value, parameter_value): } -def rdata_array_transpose(array: np.ndarray, variable: str) -> Tuple[int]: +def rdata_array_transpose(array: np.ndarray, variable: str) -> tuple[int]: if array.size == 0: return array original_parameter_dimension = derivative_parameter_dimension[variable] return np.moveaxis(array, original_parameter_dimension, -1) -def fiddy_array_transpose(array: np.ndarray, variable: str) -> Tuple[int]: +def fiddy_array_transpose(array: np.ndarray, variable: str) -> tuple[int]: if array.size == 0: return array original_parameter_dimension = derivative_parameter_dimension[variable] @@ -123,11 +124,11 @@ def run_amici_simulation_to_cached_functions( amici_model: amici.AmiciModel, *args, cache: bool = True, - output_keys: List[str] = None, - parameter_ids: List[str] = None, + output_keys: list[str] = None, + parameter_ids: list[str] = None, amici_solver: amici.AmiciSolver = None, amici_edata: amici.AmiciExpData = None, - derivative_variables: List[str] = None, + derivative_variables: list[str] = None, **kwargs, ): """Convert `amici.runAmiciSimulation` to fiddy functions. @@ -156,7 +157,7 @@ def run_amici_simulation_to_cached_functions( } def run_amici_simulation(point: Type.POINT, order: amici.SensitivityOrder): - problem_parameters = dict(zip(parameter_ids, point)) + problem_parameters = dict(zip(parameter_ids, point, strict=False)) amici_model.setParameterById(problem_parameters) amici_solver.setSensitivityOrder(order) rdata = amici.runAmiciSimulation( @@ -237,10 +238,10 @@ def derivative(point: Type.POINT, return_dict: bool = False): # (start, stop, shape) -TYPE_STRUCTURE = Tuple[int, int, Tuple[int, ...]] +TYPE_STRUCTURE = tuple[int, int, tuple[int, ...]] -def flatten(arrays: Dict[str, Type.ARRAY]) -> Type.ARRAY: +def flatten(arrays: dict[str, Type.ARRAY]) -> Type.ARRAY: flattened_value = np.concatenate([array.flat for array in arrays.values()]) return flattened_value @@ -249,7 +250,7 @@ def reshape( array: Type.ARRAY, structure: TYPE_STRUCTURE, sensitivities: bool = False, -) -> Dict[str, Type.ARRAY]: +) -> dict[str, Type.ARRAY]: reshaped = {} for variable, (start, stop, shape) in structure.items(): # array is currently "flattened" w.r.t. fiddy dimensions @@ -287,13 +288,13 @@ def reshape( def simulate_petab_to_cached_functions( petab_problem: petab.Problem, amici_model: amici.Model, - parameter_ids: List[str] = None, + parameter_ids: list[str] = None, cache: bool = True, precreate_edatas: bool = True, precreate_parameter_mapping: bool = True, simulate_petab: Callable[[Any], str] = None, **kwargs, -) -> Tuple[Type.FUNCTION, Type.FUNCTION]: +) -> tuple[Type.FUNCTION, Type.FUNCTION]: r"""Convert `amici.petab_objective.simulate_petab` to fiddy functions. Note that all gradients are provided on linear scale. The correction from @@ -373,7 +374,7 @@ def simulate_petab_to_cached_functions( ) def simulate_petab_full(point: Type.POINT, order: amici.SensitivityOrder): - problem_parameters = dict(zip(parameter_ids, point)) + problem_parameters = dict(zip(parameter_ids, point, strict=True)) amici_solver.setSensitivityOrder(order) result = simulate_petab_partial( problem_parameters=problem_parameters, diff --git a/fiddy/success.py b/fiddy/success.py index 18a93a7..1c6fdda 100644 --- a/fiddy/success.py +++ b/fiddy/success.py @@ -1,5 +1,6 @@ import abc -from typing import Any, Callable, Union +from collections.abc import Callable +from typing import Any, Union import numpy as np @@ -38,11 +39,9 @@ class Consistency(Success): def __init__( self, computer_parser: Callable[ - ["directional_derivative.Computer"], Union[float, None] - ] = None, - analysis_parser: Callable[ - ["analysis.Analysis"], Union[float, None] + ["directional_derivative.Computer"], float | None ] = None, + analysis_parser: Callable[["analysis.Analysis"], float | None] = None, rtol: float = 0.2, atol: float = 1e-15, equal_nan: bool = True, diff --git a/pyproject.toml b/pyproject.toml index 50771b6..68f5c7b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,7 @@ build-backend = "setuptools.build_meta" [tool.ruff] line-length = 79 +target-version = "py310" lint.select = [ "F", # Pyflakes "I", # isort diff --git a/tests/extensions/amici/test_amici.py b/tests/extensions/amici/test_amici.py index 3edf0d7..b433ae4 100644 --- a/tests/extensions/amici/test_amici.py +++ b/tests/extensions/amici/test_amici.py @@ -138,6 +138,7 @@ def test_simulate_petab_to_functions(problem_generator, scaled_parameters): zip( petab_problem.parameter_df.index, point, + strict=True, ) ) ).values()