diff --git a/.gitignore b/.gitignore index e06d34a7..d2e6f40f 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,4 @@ Sandbox/ # PDM .pdm-python +.pdm-build diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aea932fe..139006bd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,13 +17,13 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.0.275 + rev: v0.0.277 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/psf/black - rev: 23.3.0 # Replace by any tag/version: https://github.com/psf/black/tags + rev: 23.7.0 # Replace by any tag/version: https://github.com/psf/black/tags hooks: - id: black language_version: python3.10 diff --git a/chemex/configuration/base.py b/chemex/configuration/base.py index d543ce60..f9b9c58f 100644 --- a/chemex/configuration/base.py +++ b/chemex/configuration/base.py @@ -1,19 +1,27 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import Any from pydantic import BaseModel, ConfigDict, model_validator -if TYPE_CHECKING: - from collections.abc import MutableMapping + +def ensure_list(variable: Any | list[Any] | None) -> list[Any]: + if isinstance(variable, list): + return variable + if variable is None: + return [] + return [variable] + + +def to_lower(string: Any) -> Any: + if isinstance(string, str): + return string.lower() + return string class BaseModelLowerCase(BaseModel): model_config = ConfigDict(str_to_lower=True) @model_validator(mode="before") - @classmethod - def to_lower_case( - cls, values: MutableMapping[str, Any] - ) -> MutableMapping[str, Any]: - return {k.lower(): v for k, v in values.items()} + def key_to_lower(cls, model: dict[str, Any]) -> dict[str, Any]: + return {to_lower(k): v for k, v in model.items()} diff --git a/chemex/configuration/conditions.py b/chemex/configuration/conditions.py index de4495b6..142900d5 100644 --- a/chemex/configuration/conditions.py +++ b/chemex/configuration/conditions.py @@ -1,10 +1,11 @@ from __future__ import annotations from functools import total_ordering -from typing import TYPE_CHECKING, Any, Literal +from typing import TYPE_CHECKING, Annotated, Any, Literal from pydantic import ( BaseModel, + BeforeValidator, Field, PositiveFloat, ValidationError, @@ -12,20 +13,23 @@ model_validator, ) +from chemex.configuration.base import to_lower from chemex.models.model import model if TYPE_CHECKING: - from collections.abc import Hashable, MutableMapping + from collections.abc import Hashable + +LabelType = Annotated[Literal["1h", "2h", "13c", "15n"], BeforeValidator(to_lower)] @total_ordering class Conditions(BaseModel, frozen=True): h_larmor_frq: PositiveFloat | None = None temperature: float | None = None - p_total: PositiveFloat | None = Field(default=None) - l_total: PositiveFloat | None = Field(default=None) + p_total: PositiveFloat | None = None + l_total: PositiveFloat | None = None d2o: float | None = Field(gt=0.0, lt=1.0, default=None) - label: tuple[Literal["1h", "2h", "13c", "15n"], ...] = () + label: tuple[LabelType, ...] = () def rounded(self) -> Conditions: h_larmor_frq = round(self.h_larmor_frq, 1) if self.h_larmor_frq else None @@ -49,7 +53,7 @@ def search_keys(self) -> set[Hashable]: @property def section(self) -> str: - parts = [] + parts: list[str] = [] if self.temperature is not None: parts.append(f"T->{self.temperature:.1f}C") if self.h_larmor_frq is not None: @@ -64,7 +68,7 @@ def section(self) -> str: @property def folder(self): - parts = [] + parts: list[str] = [] if self.temperature is not None: parts.append(f"{self.temperature:.1f}C") if self.h_larmor_frq is not None: @@ -112,39 +116,30 @@ def __lt__(self, other: Conditions) -> bool: @total_ordering class ConditionsFromFile(Conditions, frozen=True): + @model_validator(mode="before") + def key_to_lower(cls, model: dict[str, Any]) -> dict[str, Any]: + return {to_lower(k): v for k, v in model.items()} + @field_validator("d2o") - @classmethod - def validate_d2o(cls, d2o): + def validate_d2o(cls, d2o: float | None) -> float | None: if "hd" in model.name and d2o is None: - raise ValidationError() + msg = 'To use the "hd" model, d2o must be provided' + raise ValidationError(msg) return d2o @field_validator("temperature") - @classmethod - def validate_temperature(cls, temperature): + def validate_temperature(cls, temperature: float | None) -> float | None: if "eyring" in model.name and temperature is None: - raise ValidationError() + msg = 'To use the "eyring" model, "temperature" must be provided' + raise ValidationError(msg) return temperature - @field_validator("label", mode="before") - @classmethod - def set_to_lower_case(cls, label): - return tuple(value.lower() for value in label) - @model_validator(mode="after") - @classmethod def validate_p_total_l_total( cls, conditions: ConditionsFromFile ) -> ConditionsFromFile: are_not_both_set = conditions.p_total is None or conditions.l_total is None if "binding" in model.name and are_not_both_set: - msg = "Either p_total or l_total must be provided" - raise ValueError(msg) + msg = 'To use the "binding" model, "p_total" and "l_total" must be provided' + raise ValidationError(msg) return conditions - - @model_validator(mode="before") - @classmethod - def set_keys_to_lower_case( - cls, values: MutableMapping[str, Any] - ) -> MutableMapping[str, Any]: - return {k.lower(): v for k, v in values.items()} diff --git a/chemex/configuration/data.py b/chemex/configuration/data.py index b9e1f676..b391a19b 100644 --- a/chemex/configuration/data.py +++ b/chemex/configuration/data.py @@ -1,11 +1,11 @@ from __future__ import annotations from pathlib import Path -from typing import Literal +from typing import Annotated, Any, Literal -from pydantic import field_validator +from pydantic import BeforeValidator, field_validator -from chemex.configuration.base import BaseModelLowerCase +from chemex.configuration.base import BaseModelLowerCase, ensure_list from chemex.parameters.spin_system import PydanticSpinSystem @@ -14,19 +14,19 @@ class DataSettings(BaseModelLowerCase): scaled: bool = True +PathList = Annotated[list[Path], BeforeValidator(ensure_list)] + + class RelaxationDataSettings(DataSettings): error: Literal["file", "duplicates"] = "file" filter_planes: list[int] = [] - profiles: dict[PydanticSpinSystem, Path | list[Path]] = {} + profiles: dict[PydanticSpinSystem, PathList] = {} - @field_validator("profiles", mode="before") - @classmethod - def make_list(cls, v): - if isinstance(v, dict): - for key, value in v.items(): - if isinstance(value, str): - v[key] = [value] - return v + @field_validator("error", mode="before") + def to_lower(cls, error: Any) -> str: + if isinstance(error, str): + return error.lower() + return error class CestDataSettings(DataSettings): @@ -34,16 +34,13 @@ class CestDataSettings(DataSettings): filter_planes: list[int] = [] filter_offsets: list[tuple[float, float]] = [(0.0, 0.0)] filter_ref_planes: bool = False - profiles: dict[PydanticSpinSystem, list[Path]] = {} + profiles: dict[PydanticSpinSystem, PathList] = {} - @field_validator("profiles", mode="before") - @classmethod - def make_list(cls, v): - if isinstance(v, dict): - for key, value in v.items(): - if isinstance(value, str): - v[key] = [value] - return v + @field_validator("error", mode="before") + def to_lower(cls, error: Any) -> str: + if isinstance(error, str): + return error.lower() + return error class CestDataSettingsNoRef(CestDataSettings): @@ -53,3 +50,9 @@ class CestDataSettingsNoRef(CestDataSettings): class ShiftDataSettings(DataSettings): error: Literal["file", "duplicates"] = "file" scaled: bool = False + + @field_validator("error", mode="before") + def to_lower(cls, error: Any) -> str: + if isinstance(error, str): + return error.lower() + return error diff --git a/chemex/configuration/methods.py b/chemex/configuration/methods.py index 1ef7956a..9ed10c6f 100644 --- a/chemex/configuration/methods.py +++ b/chemex/configuration/methods.py @@ -2,9 +2,9 @@ import sys from dataclasses import dataclass -from typing import TYPE_CHECKING, Literal +from typing import TYPE_CHECKING, Annotated, Literal -from pydantic import ConfigDict, Field, ValidationError +from pydantic import BeforeValidator, Field, ValidationError from pydantic.types import PositiveInt from chemex.configuration.base import BaseModelLowerCase @@ -18,7 +18,7 @@ # Type definitions -AllType = Literal["*", "all", "ALL", "All", "ALl", "AlL"] +AllType = Annotated[Literal["*", "all"], BeforeValidator(str.lower)] SelectionType = list[PydanticSpinSystem] | AllType | None @@ -35,8 +35,6 @@ class Selection: class Method(BaseModelLowerCase): - model_config = ConfigDict(str_to_lower=True) - fitmethod: str = "leastsq" include: SelectionType = None exclude: SelectionType = None @@ -55,7 +53,7 @@ def selection(self) -> Selection: def read_methods(filenames: Iterable[Path]) -> Methods: - methods = {} + methods: Methods = {} for filename in filenames: methods_dict = read_toml(filename) diff --git a/chemex/configuration/parameters.py b/chemex/configuration/parameters.py index 28517092..c0e15747 100644 --- a/chemex/configuration/parameters.py +++ b/chemex/configuration/parameters.py @@ -1,22 +1,32 @@ from __future__ import annotations -from collections.abc import Iterable from dataclasses import dataclass from typing import TYPE_CHECKING, Annotated from annotated_types import Len -from pydantic import RootModel, field_validator +from pydantic import AfterValidator, BeforeValidator, RootModel +from chemex.configuration.base import ensure_list from chemex.parameters.name import ParamName from chemex.toml import read_toml_multi if TYPE_CHECKING: + from collections.abc import Iterable from pathlib import Path -# Type definitions -ValueListType = Annotated[list[float], Len(min_length=1, max_length=4)] -DefaultType = tuple[ParamName, "DefaultSetting"] -DefaultListType = list[DefaultType] + +def rename_section(section_name: str) -> str: + if section_name == "global": + return "" + return f"{section_name},nuc->" + + +ValuesType = Annotated[list[float], Len(max_length=4), BeforeValidator(ensure_list)] +LowerCaseString = Annotated[str, BeforeValidator(str.lower)] +ValuesDictType = dict[LowerCaseString, ValuesType] +SectionType = Annotated[LowerCaseString, AfterValidator(rename_section)] +ParamsConfigType = dict[SectionType, ValuesDictType] +ParamsConfigModel = RootModel[ParamsConfigType] @dataclass(frozen=True) @@ -27,42 +37,21 @@ class DefaultSetting: brute_step: float | None = None -class ParamsConfig(RootModel): - root: dict[str, dict[str, ValueListType]] - - @field_validator("root", mode="before") - @classmethod - def to_lower(cls, values): - return { - k1.lower(): {k2.lower(): v2 for k2, v2 in v1.items()} - for k1, v1 in values.items() - } - - @field_validator("root", mode="before") - @classmethod - def to_list(cls, values): - for values1 in values.values(): - for key2, values2 in values1.items(): - if not isinstance(values2, Iterable): - values1[key2] = [values2] - return values - - @field_validator("root") - @classmethod - def reorder(cls, values): - return {"global": values.pop("global", {}), **values} - - def to_defaults_list(self) -> DefaultListType: - defaults_list: DefaultListType = [] - for section, settings in self.root.items(): - prefix = f"{section}, NUC->" if section != "global" else "" - for key, values in settings.items(): - pname = ParamName.from_section(f"{prefix}{key}") - default_values = DefaultSetting(*values) - defaults_list.append((pname, default_values)) - return defaults_list +DefaultType = tuple[ParamName, DefaultSetting] +DefaultListType = list[DefaultType] + + +def build_default_list(params_config: ParamsConfigModel) -> DefaultListType: + defaults: DefaultListType = [] + for section, params in params_config.root.items(): + for key, values in params.items(): + pname = ParamName.from_section(f"{section}{key}") + default_values = DefaultSetting(*values) + defaults.append((pname, default_values)) + return defaults def read_defaults(filenames: Iterable[Path]) -> DefaultListType: config = read_toml_multi(filenames) - return ParamsConfig.model_validate(config).to_defaults_list() + param_config = ParamsConfigModel.model_validate(config) + return build_default_list(param_config) diff --git a/chemex/containers/data.py b/chemex/containers/data.py index 0cbb91ea..7226d203 100644 --- a/chemex/containers/data.py +++ b/chemex/containers/data.py @@ -3,20 +3,18 @@ from copy import deepcopy from dataclasses import dataclass, field from random import choices +from typing import TYPE_CHECKING import numpy as np -from numpy.typing import NDArray -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayInt = NDArray[np.int_] -NDArrayBool = NDArray[np.bool_] +if TYPE_CHECKING: + from chemex.typing import ArrayBool, ArrayFloat rng = np.random.default_rng() -def get_scale(exp: np.ndarray, err: np.ndarray, calc: np.ndarray) -> float: +def get_scale(exp: ArrayFloat, err: ArrayFloat, calc: ArrayFloat) -> float: try: calc_err2 = calc / err**2 return sum(exp * calc_err2) / sum(calc * calc_err2) @@ -26,14 +24,14 @@ def get_scale(exp: np.ndarray, err: np.ndarray, calc: np.ndarray) -> float: @dataclass class Data: - exp: NDArrayFloat - err: NDArrayFloat - metadata: np.ndarray = field(default_factory=lambda: np.array([])) + exp: ArrayFloat + err: ArrayFloat + metadata: ArrayFloat = field(default_factory=lambda: np.array([])) scale: float = 1.0 size: int = field(init=False) - calc: NDArrayFloat = field(init=False) - mask: NDArrayBool = field(init=False) - refs: NDArrayBool = field(init=False) + calc: ArrayFloat = field(init=False) + mask: ArrayBool = field(init=False) + refs: ArrayBool = field(init=False) def __post_init__(self): self.size = self.exp.size diff --git a/chemex/containers/dataset.py b/chemex/containers/dataset.py index b6d3aa92..83eebd1f 100644 --- a/chemex/containers/dataset.py +++ b/chemex/containers/dataset.py @@ -11,13 +11,16 @@ if TYPE_CHECKING: from pathlib import Path - from chemex.configuration.experiment import ExperimentConfig + from chemex.configuration.data import RelaxationDataSettings, ShiftDataSettings + from chemex.configuration.experiment import ExperimentConfig, ExperimentNameSettings -# Type aliases -Dataset = list[tuple[SpinSystem, Data]] + # Type aliases + Dataset = list[tuple[SpinSystem, Data]] + RelaxationConfig = ExperimentConfig[ExperimentNameSettings, RelaxationDataSettings] + ShiftConfig = ExperimentConfig[ExperimentNameSettings, ShiftDataSettings] -def load_relaxation_dataset(base_path: Path, settings: ExperimentConfig) -> Dataset: +def load_relaxation_dataset(base_path: Path, settings: RelaxationConfig) -> Dataset: data_path = normalize_path(base_path, settings.data.path) dtype = [("metadata", "f8"), ("exp", "f8"), ("err", "f8")] @@ -39,7 +42,7 @@ def load_relaxation_dataset(base_path: Path, settings: ExperimentConfig) -> Data return dataset -def load_shift_dataset(base_path: Path, settings: ExperimentConfig) -> Dataset: +def load_shift_dataset(base_path: Path, settings: ShiftConfig) -> Dataset: data_path = normalize_path(base_path, settings.data.path) shifts = np.loadtxt( diff --git a/chemex/containers/experiment.py b/chemex/containers/experiment.py index decc70d3..6f676863 100644 --- a/chemex/containers/experiment.py +++ b/chemex/containers/experiment.py @@ -17,7 +17,7 @@ from collections.abc import Iterator from pathlib import Path - from lmfit.parameter import Parameters as ParametersLF + from lmfit import Parameters as ParametersLF from chemex.configuration.methods import Selection from chemex.containers.profile import Profile @@ -57,7 +57,8 @@ def select(self, selection: Selection): include = selection.include exclude = selection.exclude profiles_all = [*self.profiles, *self.filtered_profiles] - profiles, filtered = [], [] + profiles: list[Profile] = [] + filtered: list[Profile] = [] for profile in profiles_all: included = include is None or profile.name.part_of(include) excluded = exclude is not None and profile.name.part_of(exclude) @@ -111,10 +112,10 @@ def bootstrap(self) -> Experiment: def bootstrap_ns(self, groups: list[Group]) -> Experiment: """Residue-specific bootstrap.""" - profiles = {} + profiles: dict[Group, list[Profile]] = {} for profile in self.profiles: profiles.setdefault(profile.name.groups["i"], []).append(profile) - profiles_bs_ns = [] + profiles_bs_ns: list[Profile] = [] for group in groups: profiles_bs_ns.extend(profiles.get(group, [])) return Experiment( diff --git a/chemex/containers/experiments.py b/chemex/containers/experiments.py index fe86c597..0e2805b1 100644 --- a/chemex/containers/experiments.py +++ b/chemex/containers/experiments.py @@ -18,6 +18,8 @@ from chemex.configuration.methods import Selection from chemex.containers.experiment import Experiment + from chemex.typing import ArrayFloat + # Type definitions SelectionType = list[SpinSystem] | Literal["*", "all"], None @@ -29,12 +31,13 @@ def __init__(self) -> None: @property def groups(self) -> set[Group]: - return set.union(*(experiment.groups for experiment in self)) + groups: set[Group] = set() + return groups.union(*(experiment.groups for experiment in self)) def add(self, experiment: Experiment): self._experiments[experiment.filename] = experiment - def residuals(self, params: Parameters) -> np.ndarray: + def residuals(self, params: Parameters) -> ArrayFloat: return np.asarray( list( chain.from_iterable(experiment.residuals(params) for experiment in self) @@ -79,15 +82,15 @@ def param_id_sets(self) -> list[set[str]]: @property def param_ids(self) -> set[str]: - result = set() + result: set[str] = set() return result.union(*(self.param_id_sets)) - def filter(self): + def filter(self) -> None: params = database.build_lmfit_params(self.param_ids) for experiment in self: experiment.filter(params) - def get_relevant_subset(self, param_ids) -> Experiments: + def get_relevant_subset(self, param_ids: set[str]) -> Experiments: relevant_subset = Experiments() for experiment in self: if subset := experiment.get_relevant_subset(param_ids): diff --git a/chemex/containers/profile.py b/chemex/containers/profile.py index 5486ed87..3e6a0013 100644 --- a/chemex/containers/profile.py +++ b/chemex/containers/profile.py @@ -6,9 +6,7 @@ from operator import attrgetter from typing import TYPE_CHECKING, Protocol -import numpy as np from cachetools import LRUCache, cachedmethod -from numpy.typing import NDArray if TYPE_CHECKING: from lmfit import Parameters as ParametersLF @@ -17,16 +15,14 @@ from chemex.nmr.spectrometer import Spectrometer from chemex.parameters.spin_system import SpinSystem from chemex.printers.data import Printer - -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat class PulseSequence(Protocol): - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ... - def is_reference(self, metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(self, metadata: ArrayFloat) -> ArrayBool: ... @@ -35,13 +31,6 @@ def filter(self, data: Data) -> None: ... -def _cache_key(self, params: ParametersLF) -> tuple[float, ...]: - return ( - *(params[param_id].value for param_id in self.param_ids), - *self.data.metadata, - ) - - @dataclass(order=True) class Profile: data: Data = field(compare=False) @@ -54,6 +43,12 @@ class Profile: name: SpinSystem = field(compare=True, init=False) cache: LRUCache = field(compare=False, init=False) + def _cache_key(self, params: ParametersLF) -> tuple[float, ...]: + return ( + *(params[param_id].value for param_id in self.param_ids), + *self.data.metadata, + ) + def __post_init__(self): self.name = self.spectrometer.liouvillian.spin_system self.data.refs = self.pulse_sequence.is_reference(self.data.metadata) @@ -73,7 +68,7 @@ def update_spectrometer(self, params: ParametersLF) -> None: par_values = self._get_par_values(params) self.spectrometer.update(par_values) - def calculate(self, params: ParametersLF) -> np.ndarray: + def calculate(self, params: ParametersLF) -> ArrayFloat: self.update_spectrometer(params) self.data.calc = self.pulse_sequence.calculate(self.spectrometer, self.data) if self.is_scaled: @@ -81,7 +76,7 @@ def calculate(self, params: ParametersLF) -> np.ndarray: return self.data.calc @cachedmethod(attrgetter("cache"), key=_cache_key) - def residuals(self, params: ParametersLF) -> np.ndarray: + def residuals(self, params: ParametersLF) -> ArrayFloat: residuals = (self.calculate(params) - self.data.exp) / self.data.err return residuals[self.data.mask] diff --git a/chemex/experiments/builder.py b/chemex/experiments/builder.py index 60973e33..2f31718b 100644 --- a/chemex/experiments/builder.py +++ b/chemex/experiments/builder.py @@ -1,7 +1,7 @@ from __future__ import annotations import sys -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from pydantic import ValidationError from rich.live import Live @@ -26,14 +26,17 @@ if TYPE_CHECKING: from collections.abc import MutableMapping from pathlib import Path + from typing import Any from chemex.configuration.methods import Selection from chemex.containers.dataset import Dataset + ConfigType = ExperimentConfig[Any, Any] -def _get_experiment_name(config, filename: Path): + +def _get_experiment_name(config: MutableMapping[str, Any], filename: Path): try: - return ExperimentNameConfig.parse_obj(config).experiment.name + return ExperimentNameConfig.model_validate(config).experiment.name except ValidationError: print_experiment_name_error(filename) sys.exit() @@ -58,7 +61,7 @@ def _apply_selection(dataset: Dataset, selection: Selection) -> Dataset: def _create_dataset( - filename: Path, live: Live, factory: Creators, config: ExperimentConfig + filename: Path, live: Live, factory: Creators, config: ConfigType ) -> Dataset: try: dataset = factory.create_dataset(filename.parent, config) @@ -70,8 +73,8 @@ def _create_dataset( def _create_config( - filename: Path, live: Live, factory: Creators, config_dict: MutableMapping -) -> ExperimentConfig: + filename: Path, live: Live, factory: Creators, config_dict: MutableMapping[str, Any] +) -> ConfigType: try: config = factory.create_config(config_dict) except ValidationError as e: diff --git a/chemex/experiments/catalog/cest_13c.py b/chemex/experiments/catalog/cest_13c.py index 5ec25a3d..73713ce9 100644 --- a/chemex/experiments/catalog/cest_13c.py +++ b/chemex/experiments/catalog/cest_13c.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettings from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cest_13c" @@ -82,15 +78,15 @@ class Cest13CSequence: settings: Cest13CSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata start = spectrometer.get_equilibrium() - intensities = {} + intensities: dict[float, ArrayFloat] = {} for offset in set(offsets): intensities[offset] = start diff --git a/chemex/experiments/catalog/cest_15n.py b/chemex/experiments/catalog/cest_15n.py index 918b5b87..9b339839 100644 --- a/chemex/experiments/catalog/cest_15n.py +++ b/chemex/experiments/catalog/cest_15n.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettings from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cest_15n" @@ -81,15 +77,15 @@ class Cest15NSequence: settings: Cest15NSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata start = spectrometer.get_equilibrium() - intensities = {} + intensities: dict[float, ArrayFloat] = {} for offset in set(offsets): intensities[offset] = start diff --git a/chemex/experiments/catalog/cest_15n_cw.py b/chemex/experiments/catalog/cest_15n_cw.py index 5c9fc76a..8a0d239a 100644 --- a/chemex/experiments/catalog/cest_15n_cw.py +++ b/chemex/experiments/catalog/cest_15n_cw.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettings from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cest_15n_cw" @@ -96,15 +92,15 @@ class Cest15NCwSequence: settings: Cest15NCwSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata start = spectrometer.get_start_magnetization(terms=["iz"], atom="n") - intensities = {} + intensities: dict[float, ArrayFloat] = {} for offset in set(offsets): intensities[offset] = start diff --git a/chemex/experiments/catalog/cest_15n_tr.py b/chemex/experiments/catalog/cest_15n_tr.py index 457399c1..9520e63c 100644 --- a/chemex/experiments/catalog/cest_15n_tr.py +++ b/chemex/experiments/catalog/cest_15n_tr.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettings from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cest_15n_tr" @@ -93,10 +89,10 @@ class Cest15NTrSequence: settings: Cest15NTrSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def _get_start(self, spectrometer: Spectrometer) -> np.ndarray: + def _get_start(self, spectrometer: Spectrometer) -> ArrayFloat: """TROSY: (2IzSz - Iz) / 2 ANTITROSY: (2IzSz + Iz) / 2. """ @@ -105,12 +101,12 @@ def _get_start(self, spectrometer: Spectrometer) -> np.ndarray: start -= spectrometer.get_start_magnetization(["iz"]) return start - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata start = self._get_start(spectrometer) - intensities = {} + intensities: dict[float, ArrayFloat] = {} for offset in set(offsets): intensities[offset] = start diff --git a/chemex/experiments/catalog/cest_1hn_ap.py b/chemex/experiments/catalog/cest_1hn_ap.py index 1a336dfb..44ce8002 100644 --- a/chemex/experiments/catalog/cest_1hn_ap.py +++ b/chemex/experiments/catalog/cest_1hn_ap.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettings from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -20,10 +19,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cest_1hn_ap" @@ -84,15 +80,16 @@ class Cest1HnApSequence: settings: Cest1HnApSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata start = spectrometer.get_start_magnetization(terms=self.settings.start) - intensities = {} + intensities: dict[float, ArrayFloat] = {} + for offset in set(offsets): intensities[offset] = start diff --git a/chemex/experiments/catalog/cest_1hn_ip_ap.py b/chemex/experiments/catalog/cest_1hn_ip_ap.py index fca09c59..11e4f09d 100644 --- a/chemex/experiments/catalog/cest_1hn_ip_ap.py +++ b/chemex/experiments/catalog/cest_1hn_ip_ap.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettingsNoRef from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cest_1hn_ip_ap" @@ -98,10 +94,10 @@ class Cest1HnIpApSequence: settings: Cest1HnIpApSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata spectrometer.offset_i = 0.0 @@ -114,7 +110,8 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: start = d_taud @ spectrometer.get_start_magnetization(terms=["ie"]) start = spectrometer.keep(start, components=["ie", "iz"]) - intensities = {} + intensities: dict[float, float] = {} + for offset in set(offsets): spectrometer.offset_i = offset if self.settings.eta_block > 0: diff --git a/chemex/experiments/catalog/cest_ch3_1h_ip_ap.py b/chemex/experiments/catalog/cest_ch3_1h_ip_ap.py index b1d735dd..6caa7bc6 100644 --- a/chemex/experiments/catalog/cest_ch3_1h_ip_ap.py +++ b/chemex/experiments/catalog/cest_ch3_1h_ip_ap.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettingsNoRef from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -20,10 +19,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cest_ch3_1h_ip_ap" @@ -90,10 +86,10 @@ class CestCh31HIpApSequence: settings: CestCh31HIpApSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata spectrometer.offset_i = 0.0 @@ -105,7 +101,8 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: start = d_d1 @ spectrometer.get_start_magnetization(terms=["ie"]) start = spectrometer.keep(start, components=["ie", "iz"]) - intensities = {} + intensities: dict[float, float] = {} + for offset in set(offsets): spectrometer.offset_i = offset mag = spectrometer.pulse_i(self.settings.time_t1, 0.0) @ start diff --git a/chemex/experiments/catalog/coscest_13c.py b/chemex/experiments/catalog/coscest_13c.py index a3d6168c..f583bd11 100644 --- a/chemex/experiments/catalog/coscest_13c.py +++ b/chemex/experiments/catalog/coscest_13c.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettings from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -22,10 +21,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "coscest_13c" @@ -89,10 +85,10 @@ class CosCest13CSequence: settings: CosCest13CSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def _calc_cosine_shape(self, spectrometer: Spectrometer) -> np.ndarray: + def _calc_cosine_shape(self, spectrometer: Spectrometer) -> ArrayFloat: time_t1 = self.settings.time_t1 sw = self.settings.sw cos_n = self.settings.cos_n @@ -127,7 +123,7 @@ def _calc_cosine_shape(self, spectrometer: Spectrometer) -> np.ndarray: return pulse - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata start = spectrometer.get_equilibrium() @@ -138,7 +134,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: else spectrometer.identity ) - intensities = {} + intensities: dict[float, ArrayFloat] = {} for offset in set(offsets): if self.is_reference(offset): diff --git a/chemex/experiments/catalog/coscest_1hn_ip_ap.py b/chemex/experiments/catalog/coscest_1hn_ip_ap.py index 5b42d203..92c6a9c2 100644 --- a/chemex/experiments/catalog/coscest_1hn_ip_ap.py +++ b/chemex/experiments/catalog/coscest_1hn_ip_ap.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettingsNoRef from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "coscest_1hn_ip_ap" @@ -94,10 +90,10 @@ class CosCest1HnIpApSequence: settings: CosCest1HnIpApSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def _calc_cosine_shape(self, spectrometer: Spectrometer) -> np.ndarray: + def _calc_cosine_shape(self, spectrometer: Spectrometer) -> ArrayFloat: time_t1 = self.settings.time_t1 sw = self.settings.sw cos_n = self.settings.cos_n @@ -131,7 +127,7 @@ def _calc_cosine_shape(self, spectrometer: Spectrometer) -> np.ndarray: return pulse - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata spectrometer.offset_i = 0.0 @@ -145,7 +141,8 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: start = d_d1 @ spectrometer.get_start_magnetization(terms=["ie"]) start = spectrometer.keep(start, components=["ie", "iz"]) - intensities = {} + intensities: dict[float, float] = {} + for offset in set(offsets): spectrometer.offset_i = offset if self.is_reference(offset): @@ -154,6 +151,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: else: cest = self._calc_cosine_shape(spectrometer) intensities[offset] = spectrometer.detect(cest @ start) + return np.array([intensities[offset] for offset in offsets]) diff --git a/chemex/experiments/catalog/cpmg_13c_ip.py b/chemex/experiments/catalog/cpmg_13c_ip.py index 619e5228..d61669e2 100644 --- a/chemex/experiments/catalog/cpmg_13c_ip.py +++ b/chemex/experiments/catalog/cpmg_13c_ip.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cpmg_13c_ip" @@ -75,7 +71,7 @@ def build_spectrometer( class Cpmg13CIpSequence: settings: Cpmg13CIpSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - self.settings.pw90 @@ -87,7 +83,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float delays = [self.settings.t_neg, self.settings.time_equil, *tau_cps.values()] return tau_cps, delays - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -121,7 +117,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intst[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_13co_ap.py b/chemex/experiments/catalog/cpmg_13co_ap.py index 5d43af7f..7edd81d8 100644 --- a/chemex/experiments/catalog/cpmg_13co_ap.py +++ b/chemex/experiments/catalog/cpmg_13co_ap.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cpmg_13co_ap" @@ -81,7 +77,7 @@ def build_spectrometer( class Cpmg13CoApSequence: settings: Cpmg13CoApSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - self.settings.pw90 @@ -95,7 +91,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float ] return tau_cps, delays - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -141,7 +137,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_15n_ip.py b/chemex/experiments/catalog/cpmg_15n_ip.py index 927bed9d..267bd2f2 100644 --- a/chemex/experiments/catalog/cpmg_15n_ip.py +++ b/chemex/experiments/catalog/cpmg_15n_ip.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cpmg_15n_ip" @@ -75,7 +71,7 @@ def build_spectrometer( class Cpmg15NIpSequence: settings: Cpmg15NIpSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - self.settings.pw90 @@ -87,7 +83,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float delays = [self.settings.t_neg, self.settings.time_equil, *tau_cps.values()] return tau_cps, delays - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -125,7 +121,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_15n_ip_0013.py b/chemex/experiments/catalog/cpmg_15n_ip_0013.py index 32454552..595a4b0a 100644 --- a/chemex/experiments/catalog/cpmg_15n_ip_0013.py +++ b/chemex/experiments/catalog/cpmg_15n_ip_0013.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,11 +20,9 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem + from chemex.typing import ArrayBool, ArrayFloat, ArrayInt -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] -Delays = tuple[dict[float, float], dict[float, float], list[float]] + Delays = tuple[dict[float, float], dict[float, float], list[float]] EXPERIMENT_NAME = "cpmg_15n_ip_0013" @@ -83,7 +80,7 @@ def build_spectrometer( class Cpmg15N0013IpSequence: settings: Cpmg15N0013IpSettings - def _get_delays(self, ncycs: np.ndarray) -> Delays: + def _get_delays(self, ncycs: ArrayFloat) -> Delays: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - 0.75 * self.settings.pw90 @@ -106,7 +103,7 @@ def _get_delays(self, ncycs: np.ndarray) -> Delays: ] return tau_cps, deltas, delays - def _get_phases(self, ncyc): + def _get_phases(self, ncyc: ArrayFloat) -> ArrayInt: cp_phases = np.array( [ [0, 0, 1, 3, 0, 0, 3, 1, 0, 0, 3, 1, 0, 0, 1, 3], @@ -116,7 +113,7 @@ def _get_phases(self, ncyc): indexes = np.flip(np.arange(2 * int(ncyc))) return np.take(cp_phases, indexes, mode="wrap", axis=1) - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -158,7 +155,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_15n_tr.py b/chemex/experiments/catalog/cpmg_15n_tr.py index 549d2796..9ef98eba 100644 --- a/chemex/experiments/catalog/cpmg_15n_tr.py +++ b/chemex/experiments/catalog/cpmg_15n_tr.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cpmg_15n_tr" @@ -90,7 +86,7 @@ def build_spectrometer( class Cpmg15NTrSequence: settings: Cpmg15NTrSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - self.settings.pw90 @@ -104,7 +100,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float ] return tau_cps, delays - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -145,7 +141,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intst[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_15n_tr_0013.py b/chemex/experiments/catalog/cpmg_15n_tr_0013.py index fe50b4e6..6e9ed771 100644 --- a/chemex/experiments/catalog/cpmg_15n_tr_0013.py +++ b/chemex/experiments/catalog/cpmg_15n_tr_0013.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,9 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem + from chemex.typing import ArrayBool, ArrayFloat, ArrayInt + -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] Delays = tuple[dict[float, float], dict[float, float], list[float]] @@ -95,7 +93,7 @@ def build_spectrometer( class Cpmg15NTr0013Sequence: settings: Cpmg15NTr0013Settings - def _get_delays(self, ncycs: np.ndarray) -> Delays: + def _get_delays(self, ncycs: ArrayFloat) -> Delays: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - 0.75 * self.settings.pw90 @@ -115,7 +113,7 @@ def _get_delays(self, ncycs: np.ndarray) -> Delays: ] return tau_cps, deltas, delays - def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: + def _get_phases(self, ncyc: float) -> tuple[ArrayInt, ArrayInt]: cp_phases1 = np.array( [ [1, 1, 0, 2, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 0, 2], @@ -133,7 +131,7 @@ def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: phases2 = np.take(cp_phases2, indexes, mode="wrap", axis=1) return phases1, phases2 - def _get_start(self, spectrometer: Spectrometer) -> np.ndarray: + def _get_start(self, spectrometer: Spectrometer) -> ArrayFloat: start = spectrometer.get_start_magnetization(["2izsz"]) if self.settings.s3e: if self.settings.antitrosy: @@ -143,7 +141,7 @@ def _get_start(self, spectrometer: Spectrometer) -> np.ndarray: start *= 0.5 return start - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -207,7 +205,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intst[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_1hn_ap.py b/chemex/experiments/catalog/cpmg_1hn_ap.py index 8ceb0a89..f8387c86 100644 --- a/chemex/experiments/catalog/cpmg_1hn_ap.py +++ b/chemex/experiments/catalog/cpmg_1hn_ap.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cpmg_1hn_ap" @@ -80,7 +76,7 @@ def build_spectrometer( class Cpmg1HnApSequence: settings: Cpmg1HnApSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - self.settings.pw90 @@ -97,7 +93,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float ] return tau_cps, delays - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -136,7 +132,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_1hn_ap_0013.py b/chemex/experiments/catalog/cpmg_1hn_ap_0013.py index a14bf389..211b0ef0 100644 --- a/chemex/experiments/catalog/cpmg_1hn_ap_0013.py +++ b/chemex/experiments/catalog/cpmg_1hn_ap_0013.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,11 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayInt = NDArray[np.int_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat, ArrayInt EXPERIMENT_NAME = "cpmg_1hn_ap_0013" @@ -91,7 +86,7 @@ class Cpmg1HnAp0013Sequence: settings: Cpmg1HnAp0013Settings def _get_delays( - self, ncycs: NDArrayFloat + self, ncycs: ArrayFloat ) -> tuple[dict[float, float], dict[float, float], list[float]]: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { @@ -115,7 +110,7 @@ def _get_delays( ] return tau_cps, deltas, delays - def _get_phases(self, ncyc: NDArrayFloat) -> tuple[NDArrayInt, NDArrayInt]: + def _get_phases(self, ncyc: ArrayFloat) -> tuple[ArrayInt, ArrayInt]: cp_phases1 = np.array( [ [1, 1, 2, 0, 1, 1, 0, 2, 1, 1, 0, 2, 1, 1, 2, 0], @@ -133,7 +128,7 @@ def _get_phases(self, ncyc: NDArrayFloat) -> tuple[NDArrayInt, NDArrayInt]: phases2 = np.take(cp_phases2, indexes, mode="wrap", axis=1) return phases1, phases2 - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -210,7 +205,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intst[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_ch3_13c_h2c.py b/chemex/experiments/catalog/cpmg_ch3_13c_h2c.py index 552ab036..c7608439 100644 --- a/chemex/experiments/catalog/cpmg_ch3_13c_h2c.py +++ b/chemex/experiments/catalog/cpmg_ch3_13c_h2c.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import ( @@ -25,10 +24,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cpmg_ch3_13c_h2c" @@ -86,7 +82,7 @@ def build_spectrometer( class CpmgCh313CH2cSequence: settings: CpmgCh313CH2cSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncycs_no_ref = ncycs[ncycs > 0] tau_cps = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - self.settings.pw90 @@ -100,7 +96,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float ] return tau_cps, delays - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -138,7 +134,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_ch3_1h_dq.py b/chemex/experiments/catalog/cpmg_ch3_1h_dq.py index 0deb779f..1a81a94e 100644 --- a/chemex/experiments/catalog/cpmg_ch3_1h_dq.py +++ b/chemex/experiments/catalog/cpmg_ch3_1h_dq.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat, ArrayInt EXPERIMENT_NAME = "cpmg_ch3_1h_dq" @@ -80,7 +76,7 @@ def build_spectrometer( class CpmgCh31HDqSequence: settings: CpmgCh31HDqSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncyc_no_ref = ncycs[ncycs > 0] factor = 2.0 if self.settings.comp180_flg else 1.0 tau_cps = { @@ -90,7 +86,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float delays = [self.settings.tauc, *tau_cps.values()] return tau_cps, delays - def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: + def _get_phases(self, ncyc: float) -> tuple[ArrayInt, ArrayInt]: cp_phases1 = [0, 1, 0, 1, 1, 0, 1, 0, 2, 3, 2, 3, 3, 2, 3, 2] cp_phases2 = [0, 3, 0, 3, 3, 0, 3, 0, 2, 1, 2, 1, 1, 2, 1, 2] indexes = np.arange(int(ncyc)) @@ -98,7 +94,7 @@ def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: phases2 = np.take(cp_phases2, indexes, mode="wrap") return phases1, phases2 - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Getting the starting magnetization @@ -147,7 +143,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_ch3_1h_sq.py b/chemex/experiments/catalog/cpmg_ch3_1h_sq.py index dce53c72..0740e443 100644 --- a/chemex/experiments/catalog/cpmg_ch3_1h_sq.py +++ b/chemex/experiments/catalog/cpmg_ch3_1h_sq.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat, ArrayInt EXPERIMENT_NAME = "cpmg_ch3_1h_sq" @@ -81,7 +77,7 @@ def build_spectrometer( class CpmgCh31HSqSequence: settings: CpmgCh31HSqSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: frac = 7.0 / 3.0 if self.settings.comp180_flg else 1.0 ncyc_no_ref = ncycs[ncycs > 0] tau_cps = { @@ -95,7 +91,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float delays = [self.settings.taua, *tau_cps.values()] return tau_cps, delays - def _get_phases(self) -> tuple[np.ndarray, np.ndarray]: + def _get_phases(self) -> tuple[ArrayInt, ArrayInt]: cp_phases1 = np.array([[0, 1], [1, 0]]) cp_phases2 = np.array([[0, 3], [3, 0]]) indexes = np.arange(int(self.settings.ncyc_max)) @@ -103,7 +99,7 @@ def _get_phases(self) -> tuple[np.ndarray, np.ndarray]: phases2 = np.take(cp_phases2, indexes, mode="wrap", axis=1) return phases1, phases2 - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -168,7 +164,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_ch3_1h_tq.py b/chemex/experiments/catalog/cpmg_ch3_1h_tq.py index 8c74228e..b6e735df 100644 --- a/chemex/experiments/catalog/cpmg_ch3_1h_tq.py +++ b/chemex/experiments/catalog/cpmg_ch3_1h_tq.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat, ArrayInt EXPERIMENT_NAME = "cpmg_ch3_1h_tq" @@ -80,7 +76,7 @@ def build_spectrometer( class CpmgCh31HTqSequence: settings: CpmgCh31HTqSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncyc_no_ref = ncycs[ncycs > 0] factor = 2.0 if self.settings.comp180_flg else 1.0 tau_cps = { @@ -90,7 +86,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float delays = [self.settings.tauc, *tau_cps.values()] return tau_cps, delays - def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: + def _get_phases(self, ncyc: float) -> tuple[ArrayInt, ArrayInt]: cp_phases1 = [0, 1, 0, 1, 1, 0, 1, 0, 2, 3, 2, 3, 3, 2, 3, 2] cp_phases2 = [0, 3, 0, 3, 3, 0, 3, 0, 2, 1, 2, 1, 1, 2, 1, 2] indexes = np.arange(int(ncyc)) @@ -98,7 +94,7 @@ def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: phases2 = np.take(cp_phases2, indexes, mode="wrap") return phases1, phases2 - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Getting the starting magnetization @@ -147,7 +143,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_ch3_1h_tq_diff.py b/chemex/experiments/catalog/cpmg_ch3_1h_tq_diff.py index 77a53bd3..83f98c8e 100644 --- a/chemex/experiments/catalog/cpmg_ch3_1h_tq_diff.py +++ b/chemex/experiments/catalog/cpmg_ch3_1h_tq_diff.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -22,10 +21,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat, ArrayInt EXPERIMENT_NAME = "cpmg_ch3_1h_tq_diff" @@ -92,7 +88,7 @@ def build_spectrometer( class CpmgCh31HTqDiffSequence: settings: CpmgCh31HTqDiffSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncyc_no_ref = ncycs[ncycs > 0] factor = 2.0 if self.settings.comp180_flg else 1.0 tau_cps = { @@ -102,7 +98,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float delays = [self.settings.tau, *tau_cps.values()] return tau_cps, delays - def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: + def _get_phases(self, ncyc: float) -> tuple[ArrayInt, ArrayInt]: cp_phases1 = [0, 1, 0, 1, 1, 0, 1, 0, 2, 3, 2, 3, 3, 2, 3, 2] cp_phases2 = [0, 3, 0, 3, 3, 0, 3, 0, 2, 1, 2, 1, 1, 2, 1, 2] indexes = np.arange(int(ncyc)) @@ -110,7 +106,7 @@ def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: phases2 = np.take(cp_phases2, indexes, mode="wrap") return phases1, phases2 - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Getting the starting magnetization @@ -182,7 +178,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intst[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_ch3_mq.py b/chemex/experiments/catalog/cpmg_ch3_mq.py index ffd36d9d..5929d0b6 100644 --- a/chemex/experiments/catalog/cpmg_ch3_mq.py +++ b/chemex/experiments/catalog/cpmg_ch3_mq.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cpmg_ch3_mq" @@ -68,13 +64,13 @@ def build_spectrometer( class CpmgCh3MqSequence: settings: CpmgCh3MqSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncycs_no_refs = ncycs[ncycs > 0] tau_cps = {ncyc: self.settings.time_t2 / (4.0 * ncyc) for ncyc in ncycs_no_refs} delays = [self.settings.t_zeta, *tau_cps.values()] return tau_cps, delays - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -105,7 +101,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_chd2_1h_ap.py b/chemex/experiments/catalog/cpmg_chd2_1h_ap.py index a8b35666..578335f4 100644 --- a/chemex/experiments/catalog/cpmg_chd2_1h_ap.py +++ b/chemex/experiments/catalog/cpmg_chd2_1h_ap.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import CpmgSettings, ExperimentConfig, ToBeFitted @@ -21,10 +20,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "cpmg_chd2_1h_ap" @@ -77,7 +73,7 @@ def build_spectrometer( class CpmgChd21HApSequence: settings: CpmgChd21HApSettings - def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float]]: + def _get_delays(self, ncycs: ArrayFloat) -> tuple[dict[float, float], list[float]]: ncycs_no_ref = ncycs[ncycs > 0] tau_cps: dict[float, float] = { ncyc: self.settings.time_t2 / (4.0 * ncyc) - self.settings.pw90 @@ -89,7 +85,7 @@ def _get_delays(self, ncycs: np.ndarray) -> tuple[dict[float, float], list[float delays = [self.settings.t_neg, self.settings.time_equil, *tau_cps.values()] return tau_cps, delays - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -125,7 +121,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/cpmg_hn_dq_zq.py b/chemex/experiments/catalog/cpmg_hn_dq_zq.py index b49ce69c..a3ee3036 100644 --- a/chemex/experiments/catalog/cpmg_hn_dq_zq.py +++ b/chemex/experiments/catalog/cpmg_hn_dq_zq.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import ( @@ -25,10 +24,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat, ArrayInt EXPERIMENT_NAME = "cpmg_hn_dq_zq" @@ -87,7 +83,7 @@ def build_spectrometer( class CpmgHNDqZqSequence: settings: CpmgHNDqZqSettings - def _get_tau_cps(self, ncycs: np.ndarray) -> dict[float, float]: + def _get_tau_cps(self, ncycs: ArrayFloat) -> dict[float, float]: ncycs_no_ref = ncycs[ncycs > 0] return dict( zip( @@ -98,7 +94,7 @@ def _get_tau_cps(self, ncycs: np.ndarray) -> dict[float, float]: ) ) - def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: + def _get_phases(self, ncyc: float) -> tuple[ArrayInt, ArrayInt]: nu_cpmg = ncyc / self.settings.time_t2 if nu_cpmg < NU_CPMG_LIMIT_1: cp_phases1 = [0, 1, 0, 1] @@ -114,7 +110,7 @@ def _get_phases(self, ncyc: float) -> tuple[np.ndarray, np.ndarray]: phases2 = np.take(cp_phases2, np.flip(indexes), mode="wrap") return phases1, phases2 - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Calculation of the spectrometers corresponding to all the delays @@ -143,7 +139,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: return np.array([intensities[ncyc] for ncyc in ncycs]) @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return metadata == 0 diff --git a/chemex/experiments/catalog/dcest_13c.py b/chemex/experiments/catalog/dcest_13c.py index ea90ba31..cbcb2829 100644 --- a/chemex/experiments/catalog/dcest_13c.py +++ b/chemex/experiments/catalog/dcest_13c.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettings from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -22,10 +21,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "dcest_13c" @@ -98,10 +94,10 @@ class DCest13CSequence: settings: DCest13CSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata start = spectrometer.get_equilibrium() @@ -112,7 +108,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: else spectrometer.identity ) - intensities = {} + intensities: dict[float, ArrayFloat] = {} for offset in set(offsets): if self.is_reference(offset): diff --git a/chemex/experiments/catalog/dcest_15n.py b/chemex/experiments/catalog/dcest_15n.py index 35110c59..75b51a9f 100644 --- a/chemex/experiments/catalog/dcest_15n.py +++ b/chemex/experiments/catalog/dcest_15n.py @@ -5,7 +5,6 @@ import numpy as np from numpy.linalg import matrix_power -from numpy.typing import NDArray from chemex.configuration.data import CestDataSettings from chemex.configuration.experiment import CestSettings, ExperimentConfig, ToBeFitted @@ -23,10 +22,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "dcest_15n" @@ -104,10 +100,10 @@ class DCest15NSequence: settings: DCest15NSettings @staticmethod - def is_reference(metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata start = spectrometer.get_start_magnetization(self.settings.start, "n") @@ -118,7 +114,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: else spectrometer.identity ) - intensities = {} + intensities: dict[float, ArrayFloat] = {} for offset in set(offsets): if self.is_reference(offset): diff --git a/chemex/experiments/catalog/relaxation_hznz.py b/chemex/experiments/catalog/relaxation_hznz.py index af2674e7..47f2c978 100644 --- a/chemex/experiments/catalog/relaxation_hznz.py +++ b/chemex/experiments/catalog/relaxation_hznz.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import ( @@ -24,10 +23,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "relaxation_hznz" @@ -73,7 +69,7 @@ def build_spectrometer( class RelaxationHzNzSequence: settings: RelaxationHzNzSettings - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: times = data.metadata # Getting the starting magnetization @@ -92,7 +88,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: ] ) - def is_reference(self, metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(self, metadata: ArrayFloat) -> ArrayBool: return np.full_like(metadata, False, dtype=np.bool_) diff --git a/chemex/experiments/catalog/relaxation_nz.py b/chemex/experiments/catalog/relaxation_nz.py index 5808e24f..22dcd5c1 100644 --- a/chemex/experiments/catalog/relaxation_nz.py +++ b/chemex/experiments/catalog/relaxation_nz.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import RelaxationDataSettings from chemex.configuration.experiment import ( @@ -24,10 +23,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "relaxation_nz" @@ -72,7 +68,7 @@ def build_spectrometer( class RelaxationNzSequence: settings: RelaxationNzSettings - def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: times = data.metadata # Getting the starting magnetization @@ -82,7 +78,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> np.ndarray: delays = spectrometer.delays(times) return np.array([spectrometer.detect(delay @ start) for delay in delays]) - def is_reference(self, metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(self, metadata: ArrayFloat) -> ArrayBool: return np.full_like(metadata, False, dtype=np.bool_) diff --git a/chemex/experiments/catalog/shift_15n_sq.py b/chemex/experiments/catalog/shift_15n_sq.py index 4f144427..f121857a 100644 --- a/chemex/experiments/catalog/shift_15n_sq.py +++ b/chemex/experiments/catalog/shift_15n_sq.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import ShiftDataSettings from chemex.configuration.experiment import ExperimentConfig, ShiftSettings, ToBeFitted @@ -20,10 +19,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "shift_15n_sq" @@ -58,7 +54,7 @@ def build_spectrometer( return Spectrometer(liouvillian) -def _find_nearest(array, value): +def _find_nearest(array: ArrayFloat, value: float) -> float: array = np.asarray(array) idx = (np.abs(array - value)).argmin() return array[idx] @@ -68,14 +64,14 @@ def _find_nearest(array, value): class Shift15NSqSequence: settings: Shift15NSqSettings - def calculate(self, spectrometer: Spectrometer, _data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, _data: Data) -> ArrayFloat: ppm_i = spectrometer.liouvillian.ppm_i ref_shift_i = spectrometer.par_values[self.settings.cs_i_name] * ppm_i shifts = spectrometer.calculate_shifts() shift_sq = _find_nearest(shifts, ref_shift_i) return np.array([shift_sq / ppm_i]) - def is_reference(self, metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(self, metadata: ArrayFloat) -> ArrayBool: return np.full_like(metadata, False, dtype=np.bool_) diff --git a/chemex/experiments/catalog/shift_15n_sqmq.py b/chemex/experiments/catalog/shift_15n_sqmq.py index 9d978af4..927eab32 100644 --- a/chemex/experiments/catalog/shift_15n_sqmq.py +++ b/chemex/experiments/catalog/shift_15n_sqmq.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Literal import numpy as np -from numpy.typing import NDArray from chemex.configuration.data import ShiftDataSettings from chemex.configuration.experiment import ExperimentConfig, ShiftSettings @@ -20,10 +19,7 @@ if TYPE_CHECKING: from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem - -# Type definitions -NDArrayFloat = NDArray[np.float_] -NDArrayBool = NDArray[np.bool_] + from chemex.typing import ArrayBool, ArrayFloat EXPERIMENT_NAME = "shift_15n_sqmq" @@ -56,7 +52,7 @@ def build_spectrometer( return Spectrometer(liouvillian) -def _find_nearest(array, value): +def _find_nearest(array: ArrayFloat, value: float) -> float: array = np.asarray(array) idx = (np.abs(array - value)).argmin() return array[idx] @@ -66,7 +62,7 @@ def _find_nearest(array, value): class Shift15NSqMqSequence: settings: Shift15NSqMqSettings - def calculate(self, spectrometer: Spectrometer, _data: Data) -> np.ndarray: + def calculate(self, spectrometer: Spectrometer, _data: Data) -> ArrayFloat: ref_shift_i = ( spectrometer.par_values[self.settings.cs_i_name] * spectrometer.liouvillian.ppm_i @@ -89,7 +85,7 @@ def calculate(self, spectrometer: Spectrometer, _data: Data) -> np.ndarray: ] ) - def is_reference(self, metadata: NDArrayFloat) -> NDArrayBool: + def is_reference(self, metadata: ArrayFloat) -> ArrayBool: return np.full_like(metadata, False, dtype=np.bool_) diff --git a/chemex/experiments/factories.py b/chemex/experiments/factories.py index 06c27f46..f8f2d04b 100644 --- a/chemex/experiments/factories.py +++ b/chemex/experiments/factories.py @@ -7,22 +7,25 @@ from typing import TYPE_CHECKING, Any, ClassVar from chemex.configuration.experiment import ExperimentConfig -from chemex.containers.dataset import Dataset from chemex.containers.profile import Filterer, PulseSequence from chemex.nmr.spectrometer import Spectrometer from chemex.plotters.plotter import Plotter from chemex.printers.data import Printer if TYPE_CHECKING: + from chemex.containers.data import Data from chemex.parameters.spin_system import SpinSystem -ConfigCreator = Callable[..., ExperimentConfig] -PropagatorCreator = Callable[..., Spectrometer] -SequenceCreator = Callable[..., PulseSequence] -DatasetCreator = Callable[[Path, ExperimentConfig], Dataset] -FiltererCreator = Callable[..., Filterer] -PrinterCreator = Callable[[], Printer] -PlotterCreator = Callable[..., Plotter] + Dataset = list[tuple[SpinSystem, Data]] + ConfigType = ExperimentConfig[Any, Any] + + ConfigCreator = Callable[..., ConfigType] + PropagatorCreator = Callable[..., Spectrometer] + SequenceCreator = Callable[..., PulseSequence] + DatasetCreator = Callable[[Path, ConfigType], Dataset] + FiltererCreator = Callable[..., Filterer] + PrinterCreator = Callable[[], Printer] + PlotterCreator = Callable[..., Plotter] @dataclass @@ -35,26 +38,26 @@ class Creators: printer_creator: PrinterCreator plotter_creator: PlotterCreator - def create_config(self, config_dict: MutableMapping[str, Any]) -> ExperimentConfig: + def create_config(self, config_dict: MutableMapping[str, Any]) -> ConfigType: """Create a configuration object of a specific type.""" return self.config_creator(**config_dict) def create_spectrometer( - self, config: ExperimentConfig, spin_system: SpinSystem + self, config: ConfigType, spin_system: SpinSystem ) -> Spectrometer: """Create and initialize a spectrometer of a specific type.""" return self.spectrometer_creator(config, spin_system) - def create_sequence(self, config: ExperimentConfig) -> PulseSequence: + def create_sequence(self, config: ConfigType) -> PulseSequence: """Create a sequence of a specific type.""" return self.sequence_creator(config.experiment) - def create_dataset(self, base_path: Path, settings: ExperimentConfig) -> Dataset: + def create_dataset(self, base_path: Path, settings: ConfigType) -> Dataset: """Create a dataset of a specific type.""" return self.dataset_creator(base_path, settings) def create_filterer( - self, config: ExperimentConfig, spectrometer: Spectrometer + self, config: ConfigType, spectrometer: Spectrometer ) -> Filterer: """Create a filterer used to remove undesired data points.""" return self.filterer_creator(config=config, spectrometer=spectrometer) @@ -63,7 +66,7 @@ def create_printer(self) -> Printer: """Create a filterer used to remove undesired data points.""" return self.printer_creator() - def create_plotter(self, filename: Path, config: ExperimentConfig) -> Plotter: + def create_plotter(self, filename: Path, config: ConfigType) -> Plotter: """Create a filterer used to remove undesired data points.""" return self.plotter_creator(filename=filename, config=config) diff --git a/chemex/models/kinetic/settings_2st_a_a2.py b/chemex/models/kinetic/settings_2st_a_a2.py index 85c6f9fe..3c2cdc77 100644 --- a/chemex/models/kinetic/settings_2st_a_a2.py +++ b/chemex/models/kinetic/settings_2st_a_a2.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions + from chemex.typing import ArrayFloat NAME = "2st_a_a2" @@ -20,8 +21,8 @@ def calculate_concentrations( - concentrations: np.ndarray, p_total: float, k1: float -) -> np.ndarray: + concentrations: ArrayFloat, p_total: float, k1: float +) -> ArrayFloat: p_monomer, p_dimer = concentrations return np.array( [ diff --git a/chemex/models/kinetic/settings_2st_a_a3.py b/chemex/models/kinetic/settings_2st_a_a3.py index f4979c50..e4e63906 100644 --- a/chemex/models/kinetic/settings_2st_a_a3.py +++ b/chemex/models/kinetic/settings_2st_a_a3.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions + from chemex.typing import ArrayFloat NAME = "2st_a_a3" @@ -20,8 +21,8 @@ def calculate_concentrations( - concentrations: np.ndarray, p_total: float, k1: float -) -> np.ndarray: + concentrations: ArrayFloat, p_total: float, k1: float +) -> ArrayFloat: """Calculate the concentrations of monomer and trimer.""" p_monomer, p_trimer = concentrations return np.array( diff --git a/chemex/models/kinetic/settings_2st_a_a4.py b/chemex/models/kinetic/settings_2st_a_a4.py index 7c2f7c63..ee639efc 100644 --- a/chemex/models/kinetic/settings_2st_a_a4.py +++ b/chemex/models/kinetic/settings_2st_a_a4.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions + from chemex.typing import ArrayFloat NAME = "2st_a_a4" @@ -20,8 +21,8 @@ def calculate_concentrations( - concentrations: np.ndarray, p_total: float, k1: float -) -> np.ndarray: + concentrations: ArrayFloat, p_total: float, k1: float +) -> ArrayFloat: p_monomer, p_tetramer = concentrations return np.array( [ diff --git a/chemex/models/kinetic/settings_3st_a_a2_a3.py b/chemex/models/kinetic/settings_3st_a_a2_a3.py index ad3ddba1..40738a2f 100644 --- a/chemex/models/kinetic/settings_3st_a_a2_a3.py +++ b/chemex/models/kinetic/settings_3st_a_a2_a3.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions + from chemex.typing import ArrayFloat NAME = "3st_a_a2_a3" @@ -20,8 +21,8 @@ def calculate_residuals( - concentrations: np.ndarray, p_total: float, k1: float, k2: float -) -> np.ndarray: + concentrations: ArrayFloat, p_total: float, k1: float, k2: float +) -> ArrayFloat: p_monomer, p_dimer, p_trimer = concentrations return np.array( [ diff --git a/chemex/models/kinetic/settings_3st_a_a2_a4.py b/chemex/models/kinetic/settings_3st_a_a2_a4.py index df0c20d7..66d3d1c1 100644 --- a/chemex/models/kinetic/settings_3st_a_a2_a4.py +++ b/chemex/models/kinetic/settings_3st_a_a2_a4.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions + from chemex.typing import ArrayFloat NAME = "3st_a_a2_a4" @@ -20,11 +21,11 @@ def calculate_residuals( - concentrations: np.ndarray, + concentrations: ArrayFloat, p_total: float, k1: float, k2: float, -) -> np.ndarray: +) -> ArrayFloat: p_monomer, p_dimer, p_tetramer = concentrations return np.array( [ diff --git a/chemex/models/kinetic/settings_3st_binding_2st_partner.py b/chemex/models/kinetic/settings_3st_binding_2st_partner.py index 0e944352..058fa43d 100644 --- a/chemex/models/kinetic/settings_3st_binding_2st_partner.py +++ b/chemex/models/kinetic/settings_3st_binding_2st_partner.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions + from chemex.typing import ArrayFloat NAME = "3st_binding_partner_2st" @@ -21,13 +22,13 @@ def calculate_residuals( - concentrations: np.ndarray, + concentrations: ArrayFloat, p_total: float, l_total: float, kd1: float, kd2: float, keq: float, -) -> np.ndarray: +) -> ArrayFloat: p, l1, l2, pl1, pl2 = concentrations return np.array( [ diff --git a/chemex/models/kinetic/settings_3st_double_binding.py b/chemex/models/kinetic/settings_3st_double_binding.py index 338c56d9..172dc06a 100644 --- a/chemex/models/kinetic/settings_3st_double_binding.py +++ b/chemex/models/kinetic/settings_3st_double_binding.py @@ -22,6 +22,7 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions + from chemex.typing import ArrayFloat NAME = "3st_double_binding" @@ -29,12 +30,12 @@ def calculate_residuals( - populations: np.ndarray, + populations: ArrayFloat, p_total: float, l_total: float, kd_ab: float, kd_ac: float, -) -> np.ndarray: +) -> ArrayFloat: pfree, pl1, pl2 = populations lfree = l_total - p_total + pfree return np.array( diff --git a/chemex/models/kinetic/settings_3st_induced_fit.py b/chemex/models/kinetic/settings_3st_induced_fit.py index ddecdd01..0ed2cf1c 100644 --- a/chemex/models/kinetic/settings_3st_induced_fit.py +++ b/chemex/models/kinetic/settings_3st_induced_fit.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions + from chemex.typing import ArrayFloat NAME = "3st_induced_fit" @@ -20,13 +21,13 @@ def calculate_residuals( - populations: np.ndarray, + populations: ArrayFloat, p_total: float, l_total: float, kd_ab: float, kbc: float, kcb: float, -) -> np.ndarray: +) -> ArrayFloat: pfree, pl1, pl2 = populations lfree = l_total - p_total + pfree return np.array( diff --git a/chemex/nmr/basis.py b/chemex/nmr/basis.py index b172b5a7..0065b4ac 100644 --- a/chemex/nmr/basis.py +++ b/chemex/nmr/basis.py @@ -4,12 +4,17 @@ from dataclasses import dataclass from functools import cache from itertools import permutations, product -from typing import Literal +from typing import TYPE_CHECKING, Literal import numpy as np from chemex.models.model import model +if TYPE_CHECKING: + from chemex.typing import ArrayFloat + + DictArrayFloat = dict[str, ArrayFloat] + _BASES = { "ixy": ["ix", "iy"], "iz": ["iz"], @@ -59,7 +64,7 @@ "2izsz", ], } -_TRANSITIONS: dict[str, tuple[tuple[str, str, float], ...]] = { +_TRANSITIONS = { "r2_i_{state}": (("ix", "ix", -1.0), ("iy", "iy", -1.0)), "r2_s_{state}": (("sx", "sx", -1.0), ("sy", "sy", -1.0)), "r1_i_{state}": (("iz", "iz", -1.0), ("iz", "ie", +1.0)), @@ -271,9 +276,9 @@ @cache -def _build_vectors(basis: Basis) -> dict[str, np.ndarray]: +def _build_vectors(basis: Basis) -> DictArrayFloat: size = len(basis) * len(model.states) - vectors: defaultdict[str, np.ndarray] = defaultdict(lambda: np.zeros((size, 1))) + vectors: defaultdict[str, ArrayFloat] = defaultdict(lambda: np.zeros((size, 1))) for index, (state, name) in enumerate(product(model.states, basis.components)): vectors[f"{name}_{state}"][index] = 1.0 vectors[name][index] = 1.0 @@ -295,9 +300,9 @@ def _get_indices( return (rows, cols), vals -def _build_spin_matrices(basis: Basis) -> dict[str, np.ndarray]: +def _build_spin_matrices(basis: Basis) -> DictArrayFloat: size = len(basis) * len(model.states) - matrices: dict[str, np.ndarray] = defaultdict(lambda: np.zeros((size, size))) + matrices: DictArrayFloat = defaultdict(lambda: np.zeros((size, size))) for transition_name, state in product(_TRANSITIONS, model.states): if not basis.type.endswith("_diff") and transition_name.startswith("d_"): continue @@ -308,8 +313,8 @@ def _build_spin_matrices(basis: Basis) -> dict[str, np.ndarray]: return matrices -def _build_exchange_matrices(basis: Basis) -> dict[str, np.ndarray]: - matrices: dict[str, np.ndarray] = {} +def _build_exchange_matrices(basis: Basis) -> DictArrayFloat: + matrices: DictArrayFloat = {} for (i1, s1), (i2, s2) in permutations(enumerate(model.states), r=2): name = f"k{s1}{s2}" matrix = np.zeros((len(model.states), len(model.states))) @@ -319,7 +324,7 @@ def _build_exchange_matrices(basis: Basis) -> dict[str, np.ndarray]: @cache -def _build_matrices(basis: Basis) -> dict[str, np.ndarray]: +def _build_matrices(basis: Basis) -> DictArrayFloat: return _build_exchange_matrices(basis) | _build_spin_matrices(basis) @@ -346,11 +351,11 @@ def atoms(self): } @property - def vectors(self) -> dict[str, np.ndarray]: + def vectors(self) -> DictArrayFloat: return dict(_build_vectors(self)) @property - def matrices(self) -> dict[str, np.ndarray]: + def matrices(self) -> DictArrayFloat: return _build_matrices(self) @property diff --git a/chemex/nmr/constants.py b/chemex/nmr/constants.py index fbf0e802..6f0d857f 100644 --- a/chemex/nmr/constants.py +++ b/chemex/nmr/constants.py @@ -9,9 +9,13 @@ from collections import Counter from dataclasses import dataclass +from typing import TYPE_CHECKING import numpy as np +if TYPE_CHECKING: + from chemex.typing import ArrayFloat + GAMMA = { "h": 26.752_212_8e07, "q": 26.752_212_8e07, @@ -229,8 +233,8 @@ @dataclass class Distribution: - values: np.ndarray - weights: np.ndarray + values: ArrayFloat + weights: ArrayFloat def get_multiplet(symbol: str, nucleus: str) -> Distribution: diff --git a/chemex/nmr/liouvillian.py b/chemex/nmr/liouvillian.py index 7d3c0dc2..786b8444 100644 --- a/chemex/nmr/liouvillian.py +++ b/chemex/nmr/liouvillian.py @@ -28,6 +28,8 @@ from chemex.configuration.conditions import Conditions from chemex.nmr.basis import Basis from chemex.parameters.spin_system import SpinSystem + from chemex.typing import ArrayFloat + _RE_COMP = re.compile(r"\[(.+?)\]") @@ -36,7 +38,7 @@ def _make_gaussian( value: float, scale: float, res: int -) -> tuple[np.ndarray, np.ndarray]: +) -> tuple[ArrayFloat, ArrayFloat]: if scale not in (0.0, np.inf) and res > 1: grid = np.linspace(-2.0, 2.0, res) dist = grid * scale + 1.0 @@ -64,7 +66,7 @@ def __init__(self, spin_system: SpinSystem, basis: Basis, conditions: Conditions self.matrices = basis.matrices.copy() self._matrices_ref = self.matrices.copy() self._detection: str = "" - self._detect_vector: np.ndarray = np.array([]) + self._detect_vector: ArrayFloat = np.array([]) self._q_order_i = _Q_ORDER_I.get(self.basis.extension, 1.0) scale = -2.0 * np.pi * self.h_frq self.ppm_i = scale * SIGNED_XI_RATIO.get(basis.atoms.get("i", ""), 1.0) @@ -220,7 +222,7 @@ def gradient_dephasing(self, value: float): self._build_base_liouvillian() @property - def l_free(self) -> np.ndarray: + def l_free(self) -> ArrayFloat: return sum( ( self._l_base, @@ -234,7 +236,7 @@ def l_free(self) -> np.ndarray: ) @property - def weights(self) -> np.ndarray: + def weights(self) -> ArrayFloat: return self._b1_i_weights * self._jeff_i_weights @property @@ -245,10 +247,10 @@ def detection(self): def detection(self, value: str): self._detection = value expr = _RE_COMP.sub(r'self.vectors.get("\g<1>")', value) - vector: np.ndarray = eval(expr) + vector: ArrayFloat = eval(expr) self._detect_vector = vector.transpose() - def detect(self, magnetization: np.ndarray) -> float: + def detect(self, magnetization: ArrayFloat) -> float: shape = -1, *magnetization.shape[-2:] mag_weighted = self.weights * magnetization mag = mag_weighted.reshape(shape).sum(axis=0) @@ -257,7 +259,7 @@ def detect(self, magnetization: np.ndarray) -> float: detected = np.sign(detected.real) * np.abs(detected) return float(detected) - def get_equilibrium(self) -> np.ndarray: + def get_equilibrium(self) -> ArrayFloat: mag = np.zeros((self.size, 1)) for state, (name, atom) in product(model.states, self.basis.atoms.items()): scale = self.par_values.get(f"p{state}", 0.0) * XI_RATIO.get(atom, 1.0) @@ -267,7 +269,7 @@ def get_equilibrium(self) -> np.ndarray: def get_start_magnetization( self, terms: Iterable[str], atom: str = "h" - ) -> np.ndarray: + ) -> ArrayFloat: ratio = XI_RATIO.get(atom, 1.0) mag = np.zeros((self.size, 1)) for term, state, (comp, vector) in product( @@ -277,15 +279,15 @@ def get_start_magnetization( mag += self.par_values[f"p{state}"] * ratio * vector return mag - def keep(self, magnetization: np.ndarray, components: Iterable[str]) -> np.ndarray: + def keep(self, magnetization: ArrayFloat, components: Iterable[str]) -> ArrayFloat: keep = sum( (self.vectors[name] for name in components), start=np.zeros((self.size, 1)) ) keep[keep > 0] = 1.0 return keep * magnetization - def offsets_to_ppms(self, offsets: np.ndarray) -> np.ndarray: + def offsets_to_ppms(self, offsets: ArrayFloat) -> ArrayFloat: return self.carrier_i + 2.0 * np.pi * offsets / abs(self.ppm_i) - def ppms_to_offsets(self, ppms: np.ndarray | float) -> np.ndarray | float: + def ppms_to_offsets(self, ppms: ArrayFloat | float) -> ArrayFloat | float: return (ppms - self.carrier_i) * abs(self.ppm_i) / (2.0 * np.pi) diff --git a/chemex/nmr/rates.py b/chemex/nmr/rates.py index 7ac5cf3c..76235f97 100644 --- a/chemex/nmr/rates.py +++ b/chemex/nmr/rates.py @@ -12,9 +12,10 @@ if TYPE_CHECKING: from chemex.configuration.conditions import Conditions from chemex.nmr.basis import Basis + from chemex.typing import ArrayFloat -# Type definition -T = TypeVar("T", float, np.ndarray) + # Type definition + T = TypeVar("T", float, ArrayFloat) def _calculate_jw(tauc: float, s2: float, w: T) -> T: @@ -28,10 +29,10 @@ class RatesIS: ris3: float rih3: float rsh3: float - csa_i: np.ndarray - csa_s: np.ndarray - phi_i: np.ndarray - phi_s: np.ndarray + csa_i: ArrayFloat + csa_s: ArrayFloat + phi_i: ArrayFloat + phi_s: ArrayFloat def __init__(self): self.gh = GAMMA["h"] @@ -287,7 +288,7 @@ def get_model_free_expressions(basis: Basis, conditions: Conditions) -> dict[str h_frq_str = f"{conditions.h_larmor_frq}" has_h_exchange = basis.spin_system in {"nh", "hn"} - model_free_expr = {} + model_free_expr: dict[str, str] = {} for state, name in product(model.states, _RATE_NAMES): rate_name = f"{name}_{state}" khh = f", {{khh_{state}}}" if has_h_exchange else "" diff --git a/chemex/nmr/spectrometer.py b/chemex/nmr/spectrometer.py index 947b820f..24929a98 100644 --- a/chemex/nmr/spectrometer.py +++ b/chemex/nmr/spectrometer.py @@ -13,13 +13,17 @@ from chemex.nmr.constants import Distribution from chemex.nmr.liouvillian import LiouvillianIS + from chemex.typing import ArrayFloat + + DictArrayFloat = dict[str, ArrayFloat] + SMALL_VALUE = 1e-6 def calculate_propagators( - liouv: np.ndarray, delays: float | Iterable[float], dephasing: bool = False -) -> np.ndarray: + liouv: ArrayFloat, delays: float | Iterable[float], dephasing: bool = False +) -> ArrayFloat: delays_ = np.asarray(delays).reshape(-1) shape = liouv.shape propagator_list = [] @@ -42,7 +46,7 @@ def _get_key(liouvillian: LiouvillianIS, *args, **kwargs): @cached(cache={}, key=_get_key) -def _make_perfect180(liouvillian: LiouvillianIS, spin: str) -> np.ndarray: +def _make_perfect180(liouvillian: LiouvillianIS, spin: str) -> ArrayFloat: size = liouvillian.size identity = np.eye(size).reshape((1, 1, size, size)) compx, compy, compz = (f"{spin}{axis}" for axis in "xyz") @@ -58,7 +62,7 @@ def _make_perfect180(liouvillian: LiouvillianIS, spin: str) -> np.ndarray: @cached(cache={}, key=_get_key) -def _make_perfect90(liouvillian: LiouvillianIS, spin: str) -> np.ndarray: +def _make_perfect90(liouvillian: LiouvillianIS, spin: str) -> ArrayFloat: size = liouvillian.size zeros = np.zeros((size, size)) rot = liouvillian.matrices.get(f"b1x_{spin}", zeros) @@ -66,7 +70,7 @@ def _make_perfect90(liouvillian: LiouvillianIS, spin: str) -> np.ndarray: @cached(cache={}, key=_get_key) -def _get_phases(liouvillian: LiouvillianIS) -> dict[str, np.ndarray]: +def _get_phases(liouvillian: LiouvillianIS) -> DictArrayFloat: phases = {} size = liouvillian.size zeros = np.zeros((size, size)) @@ -77,7 +81,7 @@ def _get_phases(liouvillian: LiouvillianIS) -> dict[str, np.ndarray]: class Spectrometer: - def _add_phases(self, propagator: np.ndarray, spin: str = "i") -> np.ndarray: + def _add_phases(self, propagator: ArrayFloat, spin: str = "i") -> ArrayFloat: phases = self._phases[spin] return np.array([phases[i] @ propagator @ phases[-i] for i in range(4)]) @@ -103,7 +107,7 @@ def __init__(self, liouvillian: LiouvillianIS) -> None: self._p240_i = np.array(0.0) self._p180_s = np.array(0.0) - def keep(self, magnetization: np.ndarray, components: Iterable[str]) -> np.ndarray: + def keep(self, magnetization: ArrayFloat, components: Iterable[str]) -> ArrayFloat: return self.liouvillian.keep(magnetization, components) def update(self, par_values: dict[str, float]) -> None: @@ -207,12 +211,12 @@ def jeff_i(self, value: Distribution): self.calculate_i_flag = True self.calculate_s_flag = True - def get_equilibrium(self) -> np.ndarray: + def get_equilibrium(self) -> ArrayFloat: return self.liouvillian.get_equilibrium() def get_start_magnetization( self, terms: Iterable[str], atom: str = "h" - ) -> np.ndarray: + ) -> ArrayFloat: return self.liouvillian.get_start_magnetization(terms=terms, atom=atom) @property @@ -223,7 +227,7 @@ def detection(self) -> str: def detection(self, value: str): self.liouvillian.detection = value - def detect(self, magnetization: np.ndarray) -> float: + def detect(self, magnetization: ArrayFloat) -> float: return self.liouvillian.detect(magnetization) @property @@ -236,7 +240,7 @@ def gradient_dephasing(self, value: float): self.calculate_i_flag = True self.calculate_s_flag = True - def delays(self, times: float | Iterable[float]) -> np.ndarray: + def delays(self, times: float | Iterable[float]) -> ArrayFloat: return calculate_propagators(self.liouvillian.l_free, times) def pulse_i( @@ -244,7 +248,7 @@ def pulse_i( times: float | Iterable[float], phase: float, scale: float = 1.0, - ) -> np.ndarray: + ) -> ArrayFloat: dephased = self.b1_i_inh_scale == np.inf rad = phase * np.pi * 0.5 liouv = ( @@ -259,7 +263,7 @@ def pulse_s( times: float | Iterable[float], phase: float, scale: float = 1.0, - ) -> np.ndarray: + ) -> ArrayFloat: rad = phase * np.pi * 0.5 liouv = ( self.liouvillian.l_free @@ -270,7 +274,7 @@ def pulse_s( def pulse_is( self, times: float | Iterable[float], phase_i: float, phase_s: float - ) -> np.ndarray: + ) -> ArrayFloat: dephased = self.b1_i_inh_scale == np.inf liouv = ( self.liouvillian.l_free @@ -283,7 +287,7 @@ def pulse_is( def shaped_pulse_i( self, pw: float, amplitudes: Sequence[float], phases: Iterable[float] - ) -> np.ndarray: + ) -> ArrayFloat: time = pw / len(amplitudes) pairs = list(zip(amplitudes, phases, strict=True)) pulses = { @@ -300,34 +304,34 @@ def _calculate_base_pulses_i(self) -> None: self._p90_i, self._p180_i, self._p240_i = pulses.swapaxes(0, 1) @property - def p90_i(self) -> np.ndarray: + def p90_i(self) -> ArrayFloat: self._calculate_base_pulses_i() return self._p90_i @property - def p180_i(self) -> np.ndarray: + def p180_i(self) -> ArrayFloat: self._calculate_base_pulses_i() return self._p180_i @property - def p240_i(self) -> np.ndarray: + def p240_i(self) -> ArrayFloat: self._calculate_base_pulses_i() return self._p240_i @property - def p9018090_i_1(self) -> np.ndarray: + def p9018090_i_1(self) -> ArrayFloat: return self.p90_i[[3, 0, 1, 2]] @ self.p180_i @ self.p90_i[[3, 0, 1, 2]] @property - def p9018090_i_2(self) -> np.ndarray: + def p9018090_i_2(self) -> ArrayFloat: return self.p90_i[[1, 2, 3, 0]] @ self.p180_i @ self.p90_i[[1, 2, 3, 0]] @property - def p9024090_i_1(self) -> np.ndarray: + def p9024090_i_1(self) -> ArrayFloat: return self.p90_i[[3, 0, 1, 2]] @ self.p240_i @ self.p90_i[[3, 0, 1, 2]] @property - def p9024090_i_2(self) -> np.ndarray: + def p9024090_i_2(self) -> ArrayFloat: return self.p90_i[[1, 2, 3, 0]] @ self.p240_i @ self.p90_i[[1, 2, 3, 0]] def _calculate_base_pulses_s(self) -> None: @@ -338,11 +342,11 @@ def _calculate_base_pulses_s(self) -> None: self._p180_s = pulses.swapaxes(0, 1) @property - def p180_s(self) -> np.ndarray: + def p180_s(self) -> ArrayFloat: self._calculate_base_pulses_s() return self._p180_s - def p9024090_nh(self, reverse: bool = False) -> np.ndarray: + def p9024090_nh(self, reverse: bool = False) -> ArrayFloat: ph_n = 1 if reverse else 3 ph_h = 3 if reverse else 1 pw240i, pw9024090i = np.array([8.0, 14.0]) * self._pw90_i / 3.0 @@ -371,21 +375,21 @@ def p9024090_nh(self, reverse: bool = False) -> np.ndarray: return self._add_phases(self._add_phases(pw9024090is_xx, "s"), "i") @property - def p9024090_nh_1(self) -> np.ndarray: + def p9024090_nh_1(self) -> ArrayFloat: return self.p9024090_nh() @property - def p9024090_nh_2(self) -> np.ndarray: + def p9024090_nh_2(self) -> ArrayFloat: return self.p9024090_nh(reverse=True) - def calculate_shifts(self) -> np.ndarray: + def calculate_shifts(self) -> ArrayFloat: liouv = self.liouvillian.l_free.reshape( (self.liouvillian.size, self.liouvillian.size) ) return eigvals(liouv).imag - def offsets_to_ppms(self, offsets: np.ndarray) -> np.ndarray: + def offsets_to_ppms(self, offsets: ArrayFloat) -> ArrayFloat: return self.liouvillian.offsets_to_ppms(offsets) - def ppms_to_offsets(self, ppms: np.ndarray | float) -> np.ndarray | float: + def ppms_to_offsets(self, ppms: ArrayFloat | float) -> ArrayFloat | float: return self.liouvillian.ppms_to_offsets(ppms) diff --git a/chemex/optimize/fitting.py b/chemex/optimize/fitting.py index 14bfb2dd..0ce61123 100644 --- a/chemex/optimize/fitting.py +++ b/chemex/optimize/fitting.py @@ -53,7 +53,7 @@ def _run_statistics( params_lf = database.build_lmfit_params(experiments.param_ids) ids_vary = [param.name for param in params_lf.values() if param.vary] - for statistic_name, iter_nb in statistics.dict().items(): + for statistic_name, iter_nb in statistics.model_dump().items(): if iter_nb is None: continue diff --git a/chemex/optimize/gridding.py b/chemex/optimize/gridding.py index 551c5b00..7db47378 100644 --- a/chemex/optimize/gridding.py +++ b/chemex/optimize/gridding.py @@ -30,22 +30,25 @@ from lmfit.parameter import Parameters from chemex.containers.experiments import Experiments + from chemex.typing import ArrayFloat @dataclass class GridResult: - grid: dict[str, np.ndarray] - chisqr: np.ndarray + grid: dict[str, ArrayFloat] + chisqr: ArrayFloat -def _set_param_values(params: Parameters, fnames: Iterable[str], values: tuple): +def _set_param_values( + params: Parameters, fnames: Iterable[str], values: tuple[float, ...] +): for fname, value in zip(fnames, values, strict=True): params[fname].value = value def run_group_grid( group: Group, - grid: dict[str, np.ndarray], + grid: dict[str, ArrayFloat], path: Path, fitmethod: str | None, ) -> GridResult: @@ -66,7 +69,7 @@ def run_group_grid( with filename.open("w") as fileout: fileout.write(print_header(group_grid)) - chisqr_list = [] + chisqr_list: list[float] = [] grid_values = product(*group_grid.values()) @@ -84,8 +87,8 @@ def run_group_grid( def _reshape_chisqr( - grid_ref: dict[str, np.ndarray], grid_result: GridResult -) -> np.ndarray: + grid_ref: dict[str, ArrayFloat], grid_result: GridResult +) -> ArrayFloat: keys = list(grid_result.grid) order = [keys.index(key) for key in grid_ref if key in keys] axes_to_reduce = tuple(sorted(set(range(len(keys))) - set(order))) @@ -104,8 +107,8 @@ def _reshape_chisqr( def _get_grids( - grid: dict[str, np.ndarray], grid_results: list[GridResult] -) -> list[dict[str, np.ndarray]]: + grid: dict[str, ArrayFloat], grid_results: list[GridResult] +) -> list[dict[str, ArrayFloat]]: grid_params = {tuple(sorted(grid_result.grid)) for grid_result in grid_results} grid_params_tmp = grid_params.copy() for params1, params2 in permutations(grid_params, 2): @@ -115,11 +118,11 @@ def _get_grids( def combine_grids( - grid: dict[str, np.ndarray], grid_results: list[GridResult] + grid: dict[str, ArrayFloat], grid_results: list[GridResult] ) -> list[GridResult]: grids = _get_grids(grid, grid_results) - results = [] + results: list[GridResult] = [] for grid_ref in grids: shape = tuple(len(values) for values in grid_ref.values()) @@ -145,11 +148,11 @@ def set_params_from_grid(grids_1d: Iterable[GridResult]): def make_grids_nd( - grid: dict[str, np.ndarray], + grid: dict[str, ArrayFloat], grids_combined: list[GridResult], ndim: int, ) -> list[GridResult]: - grids = [] + grids: list[GridResult] = [] parameters = database.get_parameters(grid) ids = sorted(grid, key=lambda x: parameters[x].param_name) for selection in combinations(ids, ndim): diff --git a/chemex/optimize/grouping.py b/chemex/optimize/grouping.py index 87e58202..5566609c 100644 --- a/chemex/optimize/grouping.py +++ b/chemex/optimize/grouping.py @@ -81,7 +81,7 @@ def create_groups(experiments: Experiments) -> list[Group]: f"Group [magenta]{{group_name}}[/] ({{index}}/{len(id_groups)})" ) - groups = [] + groups: list[Group] = [] for index, (pname, param_ids) in enumerate(id_groups, start=1): group_name = group_name_template.format(index=index, pname=pname) group_path = Path(path_name_template.format(group_name=group_name)) diff --git a/chemex/optimize/minimizer.py b/chemex/optimize/minimizer.py index dc17a58b..e19d2426 100644 --- a/chemex/optimize/minimizer.py +++ b/chemex/optimize/minimizer.py @@ -15,9 +15,8 @@ ) if TYPE_CHECKING: - import numpy as np - from chemex.containers.experiments import Experiments + from chemex.typing import ArrayFloat @dataclass @@ -26,7 +25,7 @@ class Reporter: threshold: float = -1.0e-3 def iter_cb( - self, params: Parameters, iteration: int, residuals: np.ndarray + self, params: Parameters, iteration: int, residuals: ArrayFloat ) -> None: chisqr = (residuals**2).sum() change = (chisqr - self.last_chisqr) / self.last_chisqr diff --git a/chemex/parameters/database.py b/chemex/parameters/database.py index 4ebeb9d6..3bd44ce4 100644 --- a/chemex/parameters/database.py +++ b/chemex/parameters/database.py @@ -27,6 +27,8 @@ from chemex.configuration.methods import Method from chemex.configuration.parameters import DefaultListType from chemex.parameters.setting import Parameters, ParamSetting + from chemex.typing import ArrayFloat + _PARAM_NAME = r"\[(.+?)\]" _FLOAT = r"[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?" @@ -46,12 +48,12 @@ def add(self, param_name: ParamName) -> None: def get_matching_ids(self, param_name: ParamName) -> set[str]: search_keys = param_name.search_keys - return set.intersection( + return set[str].intersection( *(self._index.get(search_key, set()) for search_key in search_keys) ) -def _convert_grid_expression_to_values(grid_expression: str) -> np.ndarray: +def _convert_grid_expression_to_values(grid_expression: str) -> ArrayFloat: if match := re.match(_LINEAR, grid_expression): return np.linspace( float(match.group("start")), @@ -86,7 +88,7 @@ def add_multiple(self, parameters: Parameters) -> None: self._add(parameter) def get_parameters(self, param_ids: Iterable[str]) -> Parameters: - relevant_ids = set() + relevant_ids: set[str] = set() pool_ids = set(self._parameters) & set(param_ids) @@ -155,7 +157,7 @@ def _count_per_section(self, param_ids: set[str]) -> Counter[str]: def set_vary(self, section_names: Sequence[str], vary: bool) -> Counter[str]: parameters = self._parameters - ids_modified = set() + ids_modified: set[str] = set() ids_pool = { param_id for param_id, setting in parameters.items() @@ -182,7 +184,7 @@ def _get_ids_left(self, expression: str) -> set[str]: return self.get_matching_ids(ParamName.from_section(expression)) def _get_ids_right(self, expression: str) -> dict[str, set[str]]: - ids_right = {} + ids_right: dict[str, set[str]] = {} for match in re.finditer(_PARAM_NAME, expression): param_name = ParamName.from_section(match.group(1)) ids_right[match.group(0)] = self.get_matching_ids(param_name) @@ -209,7 +211,7 @@ def _set_expression(self, expression: str, ids_pool: set[str]) -> set[str]: return ids_left def set_expressions(self, expression_list: Sequence[str]) -> Counter[str]: - ids_modified = set() + ids_modified: set[str] = set() ids_pool = set(self._parameters) for expression in reversed(expression_list): @@ -219,10 +221,10 @@ def set_expressions(self, expression_list: Sequence[str]) -> Counter[str]: return self._count_per_section(ids_modified) - def parse_grid(self, grid_entries: list[str]) -> dict[str, np.ndarray]: + def parse_grid(self, grid_entries: list[str]) -> dict[str, ArrayFloat]: ids_pool = set(self._parameters) - grid_values: dict[str, np.ndarray] = {} + grid_values: dict[str, ArrayFloat] = {} for entry in reversed(grid_entries): name, expression, *something_else = entry.replace(" ", "").split("=") @@ -293,7 +295,7 @@ def get_value(self, param_id: str) -> float | None: def build_lmfit_params(self, param_ids: Iterable[str]) -> ParametersLF: return self.database.build_lmfit_params(param_ids) - def sort(self): + def sort(self) -> None: self.database.sort() def update_from_parameters(self, parameters: ParametersLF) -> None: @@ -324,7 +326,7 @@ def fix_all(self) -> None: def set_expressions(self, expression_list: Sequence[str]) -> Counter[str]: return self.database.set_expressions(expression_list) - def parse_grid(self, grid_entries: list[str]) -> dict[str, np.ndarray]: + def parse_grid(self, grid_entries: list[str]) -> dict[str, ArrayFloat]: return self.database.parse_grid(grid_entries) diff --git a/chemex/parameters/factory.py b/chemex/parameters/factory.py index 510ffb93..3199a5c6 100644 --- a/chemex/parameters/factory.py +++ b/chemex/parameters/factory.py @@ -10,12 +10,16 @@ from chemex.parameters.spins import build_spin_param_settings if TYPE_CHECKING: + from typing import Any + from chemex.configuration.conditions import Conditions from chemex.configuration.experiment import ExperimentConfig from chemex.nmr.basis import Basis from chemex.nmr.liouvillian import LiouvillianIS from chemex.parameters.spin_system import SpinSystem + ConfigType = ExperimentConfig[Any, Any] + @cache def _build_settings( @@ -68,9 +72,7 @@ def _build_parameters( return name_map, parameters -def create_parameters( - config: ExperimentConfig, liouvillian: LiouvillianIS -) -> dict[str, str]: +def create_parameters(config: ConfigType, liouvillian: LiouvillianIS) -> dict[str, str]: # A copy is done because the output of '_build_settings' is cached settings, settings_mf = _build_settings(liouvillian.basis, config.conditions) diff --git a/chemex/parameters/name.py b/chemex/parameters/name.py index 9498f4f0..9b2326e2 100644 --- a/chemex/parameters/name.py +++ b/chemex/parameters/name.py @@ -32,7 +32,7 @@ ) -def _parse(re_to_match: Pattern, text: str) -> dict[str, str]: +def _parse(re_to_match: Pattern[str], text: str) -> dict[str, str]: return { key: value for match in re_to_match.finditer(text) @@ -70,7 +70,7 @@ def _expand(string: str) -> str: class ParamName: name: str = "" spin_system: SpinSystem = field(default_factory=SpinSystem) - conditions: Conditions = field(default_factory=Conditions.construct) + conditions: Conditions = field(default_factory=Conditions.model_construct) search_keys: set[Hashable] = field(init=False, compare=False) def __post_init__(self): @@ -87,7 +87,7 @@ def from_section(cls, section: str = "") -> ParamName: if name is None: name = "" spin_system = SpinSystem(parsed.get("spin_system")) - conditions = Conditions.parse_obj(parsed) + conditions = Conditions.model_validate(parsed) return ParamName(name, spin_system, conditions) @cached_property diff --git a/chemex/parameters/setting.py b/chemex/parameters/setting.py index 509f0b07..de70c798 100644 --- a/chemex/parameters/setting.py +++ b/chemex/parameters/setting.py @@ -123,7 +123,7 @@ def id(self) -> str: return self.param_name.id @property - def args(self) -> tuple: + def args(self) -> tuple[str, float | None, bool | None, float, float, str]: return self.id, self.value, self.vary, self.min, self.max, self.expr def set(self, default_setting: DefaultSetting) -> None: diff --git a/chemex/parameters/spin_system.py b/chemex/parameters/spin_system.py index 530630f4..c070ed6d 100644 --- a/chemex/parameters/spin_system.py +++ b/chemex/parameters/spin_system.py @@ -5,7 +5,7 @@ from functools import cache, cached_property, total_ordering from itertools import chain, combinations from re import search -from typing import TYPE_CHECKING, Annotated, Literal +from typing import TYPE_CHECKING, Annotated, Any, Literal from pydantic import PlainValidator @@ -120,7 +120,7 @@ class Group: def __init__(self, name: str) -> None: self.symbol, self.number, self.suffix = self.parse_group(name.strip().upper()) self.symbol = AAA_TO_A.get(self.symbol, self.symbol) - self.search_keys: set = {self} if self else set() + self.search_keys: set[Hashable] = {self} if self else set() def parse_group(self, name: str) -> tuple[str, int, str]: if found := search("[0-9]+", name.strip().upper()): @@ -210,7 +210,7 @@ def __str__(self) -> str: return self.name -def powerset(iterable): +def powerset(iterable: Iterable[Any]) -> Iterable[Any]: "powerset([1,2,3]) --> (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)." s = list(iterable) return chain.from_iterable(combinations(s, r) for r in range(1, len(s) + 1)) @@ -224,7 +224,7 @@ def _parse_spin_system(name: str) -> dict[str, Spin]: if not name: return {} split = name.split("-") - spins = {} + spins: dict[str, Spin] = {} last_group = None for short_name, name_spin in zip(SPIN_ALIASES, split, strict=False): spin = Spin(name_spin, last_group) @@ -234,7 +234,7 @@ def _parse_spin_system(name: str) -> dict[str, Spin]: @staticmethod def _spins2name(spins: Iterable[Spin]) -> str: - spin_names = [] + spin_names: list[str] = [] last_group: Group = Group("") for spin in spins: spin_name = str(spin.atom) if spin.group == last_group else str(spin) @@ -254,12 +254,12 @@ def __init__(self, name: str | int | None = None): *(spin.search_keys for spin in self.spins.values()) ) - def __deepcopy__(self, memo) -> SpinSystem: + def __deepcopy__(self, memo: dict[Any, Any]) -> SpinSystem: return SpinSystem(self.name) @cached_property def names(self) -> dict[str, str]: - result = {} + result: dict[str, str] = {} for alias_set in powerset(SPIN_ALIASES): if set(alias_set).issubset(self.spins): key = "".join(alias_set) @@ -288,9 +288,7 @@ def nuclei(self) -> dict[str, Nucleus]: return {alias: atom.nucleus for alias, atom in self.atoms.items()} def match(self, other: SpinSystem) -> bool: - if len(self.spins) != len(other.spins): - return False - spin_pairs = zip(self.spins.values(), other.spins.values(), strict=True) + spin_pairs = zip(self.spins.values(), other.spins.values(), strict=False) return all(spin.match(other_spin) for spin, other_spin in spin_pairs) def part_of(self, selection: Sequence[SpinSystem] | str) -> bool: @@ -299,7 +297,7 @@ def part_of(self, selection: Sequence[SpinSystem] | str) -> bool: return any(item.match(self) for item in selection) def correct(self, basis: Basis) -> SpinSystem: - spins = [] + spins: list[Spin] = [] last_spin = Spin("") for letter, atom in basis.atoms.items(): spin = Spin(self.spins.get(letter, last_spin).name) @@ -322,7 +320,7 @@ def build_sub_spin_system( return self return SpinSystem() - def __and__(self, other) -> SpinSystem: + def __and__(self, other: Any) -> SpinSystem: if not isinstance(other, SpinSystem): return NotImplemented if self == other: diff --git a/chemex/parameters/spins.py b/chemex/parameters/spins.py index 34b77767..cbe25a78 100644 --- a/chemex/parameters/spins.py +++ b/chemex/parameters/spins.py @@ -250,7 +250,7 @@ def _select_relevant_settings( all_settings: LocalSettings, basis: Basis ) -> LocalSettings: pool = set(all_settings) & set(basis.matrices) - selection = set() + selection: set[str] = set() while pool: name = pool.pop() selection.add(name) diff --git a/chemex/parameters/userfunctions.py b/chemex/parameters/userfunctions.py index 46dcce74..53a19b99 100644 --- a/chemex/parameters/userfunctions.py +++ b/chemex/parameters/userfunctions.py @@ -16,11 +16,13 @@ class Registry: user_function_registry: ClassVar[dict[str, Any]] = {} - def register(self, name: str, user_functions: dict[str, Callable]): + def register(self, name: str, user_functions: dict[str, Callable[[Any], Any]]): + """Register a new set of user functions.""" + self.user_function_registry[name] = user_functions """Register a new set of user functions.""" self.user_function_registry[name] = user_functions - def get(self, name: str) -> dict[str, Callable]: + def get(self, name: str) -> dict[str, Callable[[Any], Any]]: if name not in self.user_function_registry: return {} return self.user_function_registry[name] diff --git a/chemex/plotters/cest.py b/chemex/plotters/cest.py index c3d0ef31..73305bf4 100644 --- a/chemex/plotters/cest.py +++ b/chemex/plotters/cest.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Any, Generic, Protocol, TypeVar import numpy as np -import numpy.typing as npt from matplotlib.backends.backend_pdf import PdfPages from matplotlib.ticker import MaxNLocator @@ -21,6 +20,7 @@ from chemex.containers.profile import Profile from chemex.nmr.spectrometer import Spectrometer + from chemex.typing import ArrayFloat _GREY400 = "#BDBDBD" _LSTYLES = ("-", "--", "-.", ":") @@ -37,7 +37,7 @@ class CestExperimentConfig(Protocol): T = TypeVar("T", bound=CestExperimentConfig) -def estimate_sigma(values: npt.NDArray[np.float64]) -> float: +def estimate_sigma(values: ArrayFloat) -> float: """Estimates standard deviation using median to exclude outliers. Up to 50% can be bad. @@ -64,7 +64,7 @@ def __post_init__(self) -> None: sw_ppm, sw_ref = self.spectrometer.offsets_to_ppms(np.array([self.sw, 0.0])) self.sw_ppm = sw_ppm - sw_ref - def centre(self, array: np.ndarray, position: float) -> np.ndarray: + def centre(self, array: ArrayFloat, position: float) -> ArrayFloat: if self.sw == np.inf: return array cs_min = position - self.sw_ppm / 2.0 @@ -74,7 +74,7 @@ def centre(self, array: np.ndarray, position: float) -> np.ndarray: def add_resonance_positions( ax1: Axes, ax2: Axes, - cs_values: np.ndarray, + cs_values: ArrayFloat, centre: float, circular_shift: CircularShift, ) -> tuple[Axes, Axes]: @@ -96,7 +96,7 @@ def plot_dcest( name: str, data_exp: Data, data_calc: Data, - cs_values: np.ndarray, + cs_values: ArrayFloat, circular_shift: CircularShift, ): residuals = data_exp.exp - data_exp.calc @@ -168,7 +168,7 @@ def create_plot_data_calc(profile: Profile) -> Data: return data_fit -def get_state_positions(spectrometer: Spectrometer) -> np.ndarray: +def get_state_positions(spectrometer: Spectrometer) -> ArrayFloat: names = (f"cs_i_{state}" for state in "abcd") return np.array( [ diff --git a/chemex/plotters/cpmg.py b/chemex/plotters/cpmg.py index e6e9ca01..2b4a6d90 100644 --- a/chemex/plotters/cpmg.py +++ b/chemex/plotters/cpmg.py @@ -5,7 +5,6 @@ import numpy as np from matplotlib.backends.backend_pdf import PdfPages -from numpy.typing import NDArray from chemex.containers.data import Data from chemex.messages import print_plot_filename @@ -16,9 +15,8 @@ from pathlib import Path from chemex.containers.profile import Profile + from chemex.typing import ArrayFloat -# Types -NDArrayFloat = NDArray[np.float_] LARGE_ERROR = 1e15 @@ -48,8 +46,8 @@ def plot_cpmg(file_pdf: PdfPages, name: str, data_exp: Data, data_calc: Data): def intensities_to_rates( - intensities: np.ndarray, intensities0: np.ndarray, time_t2: float -) -> np.ndarray: + intensities: ArrayFloat, intensities0: ArrayFloat, time_t2: float +) -> ArrayFloat: normalized_intensities = intensities / np.mean(intensities0, axis=-1, keepdims=True) # If the normalized intensity is negative, no rate can be estimated. @@ -61,19 +59,19 @@ def intensities_to_rates( return rates -def calculate_exp_rates(data: Data, time_t2: float) -> np.ndarray: +def calculate_exp_rates(data: Data, time_t2: float) -> ArrayFloat: intensities = data.exp[~data.refs] intensities0 = data.exp[data.refs] return intensities_to_rates(intensities, intensities0, time_t2) -def calculate_calc_rates(data: Data, time_t2: float) -> np.ndarray: +def calculate_calc_rates(data: Data, time_t2: float) -> ArrayFloat: intensities = data.calc[~data.refs] intensities0 = data.exp[data.refs] return intensities_to_rates(intensities, intensities0, time_t2) -def calculate_errorbars(data: Data, rates: np.ndarray, time_t2: float) -> np.ndarray: +def calculate_errorbars(data: Data, rates: ArrayFloat, time_t2: float) -> ArrayFloat: randn = rng.standard_normal(size=(10000, 1)) randn0 = rng.standard_normal(size=(10000, 1)) @@ -86,7 +84,7 @@ def calculate_errorbars(data: Data, rates: np.ndarray, time_t2: float) -> np.nda intensities_ensemble = intensities + intensities_err * randn intensities0_ensemble = intensities0 + intensities0_err * randn0 - rates_ensemble: NDArrayFloat = intensities_to_rates( + rates_ensemble: ArrayFloat = intensities_to_rates( intensities_ensemble, intensities0_ensemble, time_t2 ) @@ -101,7 +99,7 @@ def calculate_errorbars(data: Data, rates: np.ndarray, time_t2: float) -> np.nda return np.abs(errors) -def ncycs_to_nu_cpmgs(ncycs: np.ndarray, time_t2: float) -> np.ndarray: +def ncycs_to_nu_cpmgs(ncycs: ArrayFloat, time_t2: float) -> ArrayFloat: modified_ncycs = ncycs.copy() modified_ncycs[modified_ncycs == -1] = 0.5 return modified_ncycs[modified_ncycs != 0] / time_t2 @@ -132,7 +130,7 @@ def create_plot_data_calc(profile: Profile, config: CpmgExperimentConfig) -> Dat refs = data.refs step = 2 if config.experiment.even_ncycs else 1 - ncycs = np.arange(2, max(data.metadata) + 1, step) + ncycs = np.arange(2, max(data.metadata) + 1, step, dtype=np.float_) ncycs = np.asarray(sorted(set(ncycs) | set(data.metadata[~refs]))) filler = np.zeros_like(ncycs) diff --git a/chemex/plotters/plot.py b/chemex/plotters/plot.py index ea1e782d..87af3625 100644 --- a/chemex/plotters/plot.py +++ b/chemex/plotters/plot.py @@ -9,6 +9,7 @@ from matplotlib.axes import Axes from chemex.containers.data import Data + from chemex.typing import ArrayFloat _RED100 = "#FFCDD2" _RED300 = "#E57373" @@ -28,7 +29,7 @@ def _create_fig(name: str) -> tuple[Figure, Axes, Axes]: return fig, ax1, ax2 -def get_grid(values: np.ndarray, size: int = 400, extension: float = 0.0) -> np.ndarray: +def get_grid(values: ArrayFloat, size: int = 400, extension: float = 0.0) -> ArrayFloat: value_min = np.min(values) value_max = np.max(values) extra = (value_max - value_min) * extension diff --git a/chemex/printers/parameters.py b/chemex/printers/parameters.py index 695f52da..628d208f 100644 --- a/chemex/printers/parameters.py +++ b/chemex/printers/parameters.py @@ -83,7 +83,7 @@ def _quote(text: str) -> str: def _format_strings(par_strings: dict[str, dict[str, str]]) -> str: - result = [] + result: list[str] = [] for section, key_values in par_strings.items(): result.append(f"[{_quote(section)}]") width = len(max(key_values, key=len)) diff --git a/chemex/tools/pick_cest.py b/chemex/tools/pick_cest.py index 0d26458a..cff9f44e 100644 --- a/chemex/tools/pick_cest.py +++ b/chemex/tools/pick_cest.py @@ -31,13 +31,13 @@ class Curve: def __init__(self, profile: Profile, sw: float | None = None): data = create_plot_data_exp(profile) - settings = profile.pulse_sequence.settings + settings = getattr(profile.pulse_sequence, "settings", None) delta_ppm = 0.0 if settings is not None: spectrometer = profile.spectrometer cos_n = getattr(settings, "cos_n", None) - sw = settings.sw + sw = getattr(settings, "sw", None) if cos_n is not None and cos_n % 2 == 0 and sw is not None: shifts_ppm = spectrometer.offsets_to_ppms(np.array([sw / 2.0, 0.0])) delta_ppm = shifts_ppm[0] - shifts_ppm[1] @@ -57,16 +57,16 @@ def __init__(self, profile: Profile, sw: float | None = None): else: self.spline = CubicSpline(x, y) - def get_xrange(self, sw=None): + def get_xrange(self, sw: float | None = None): if sw is None: sw = 1.0 return self.xcentre + sw * self.xrange * np.array([-0.5, 0.5]) class Buttons: - def __init__(self, experiments: Experiments, path: Path, sw: float) -> None: - self.data = {} - names = set() + def __init__(self, experiments: Experiments, path: Path, sw: float | None) -> None: + self.data: dict[SpinSystem, list[Curve]] = {} + names: set[SpinSystem] = set() for experiment in experiments: for profile in experiment: diff --git a/chemex/typing.py b/chemex/typing.py new file mode 100644 index 00000000..0836c55c --- /dev/null +++ b/chemex/typing.py @@ -0,0 +1,6 @@ +import numpy as np +from numpy.typing import NDArray + +ArrayFloat = NDArray[np.float_] +ArrayBool = NDArray[np.bool_] +ArrayInt = NDArray[np.int_] diff --git a/examples/Experiments/CPMG_15N_IP/Experiments/500mhz.toml b/examples/Experiments/CPMG_15N_IP/Experiments/500mhz.toml index fcb19cd8..e09be70d 100644 --- a/examples/Experiments/CPMG_15N_IP/Experiments/500mhz.toml +++ b/examples/Experiments/CPMG_15N_IP/Experiments/500mhz.toml @@ -1,6 +1,6 @@ [experiment] -carrier = 118.559 name = "cpmg_15n_ip" +carrier = 118.559 pw90 = 40.6625e-6 time_equil = 2.0e-3 time_t2 = 30.0e-3 diff --git a/pdm.lock b/pdm.lock index 254c5cd3..444a3f14 100644 --- a/pdm.lock +++ b/pdm.lock @@ -15,8 +15,8 @@ summary = "Safe, minimalistic evaluator of python expression using ast module" [[package]] name = "black" -version = "23.3.0" -requires_python = ">=3.7" +version = "23.7.0" +requires_python = ">=3.8" summary = "The uncompromising code formatter." dependencies = [ "click>=8.0.0", @@ -104,7 +104,7 @@ dependencies = [ [[package]] name = "matplotlib" -version = "3.7.1" +version = "3.7.2" requires_python = ">=3.8" summary = "Python plotting package" dependencies = [ @@ -115,7 +115,7 @@ dependencies = [ "numpy>=1.20", "packaging>=20.0", "pillow>=6.2.0", - "pyparsing>=2.3.1", + "pyparsing<3.1,>=2.3.1", "python-dateutil>=2.7", ] @@ -133,7 +133,7 @@ summary = "Type system extensions for programs checked with the mypy type checke [[package]] name = "numpy" -version = "1.25.0" +version = "1.25.1" requires_python = ">=3.9" summary = "Fundamental package for array computing in Python" @@ -189,7 +189,7 @@ summary = "Pygments is a syntax highlighting package written in Python." [[package]] name = "pyparsing" -version = "3.1.0" +version = "3.0.9" requires_python = ">=3.6.8" summary = "pyparsing module - Classes and methods to define and execute parsing grammars" @@ -274,32 +274,29 @@ content_hash = "sha256:d85e84207b7cef870c53c519380c3f64e37cdfd01f4fc720977de3bab {url = "https://files.pythonhosted.org/packages/4d/bd/a938d91862d48f55f57d4fd2c5ac468bd3e8f115b3334e8901ee0d5b463f/asteval-0.9.30-py3-none-any.whl", hash = "sha256:8618aae5de09804cfec7d4838b27d1d5454aa40dc4bd477468e62f5a16d1879e"}, {url = "https://files.pythonhosted.org/packages/7c/02/c26a895ec40b4f589b2fa6871ece7c03d7e2a85f60e348d6511f0bdf8fee/asteval-0.9.30.tar.gz", hash = "sha256:a3021215568186eb866bec4dce2730f0fda3863eef9ff79e2f7b6cc4a84c26df"}, ] -"black 23.3.0" = [ - {url = "https://files.pythonhosted.org/packages/06/1e/273d610249f0335afb1ddb03664a03223f4826e3d1a95170a0142cb19fb4/black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, - {url = "https://files.pythonhosted.org/packages/12/4b/99c71d1cf1353edd5aff2700b8960f92e9b805c9dab72639b67dbb449d3a/black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, - {url = "https://files.pythonhosted.org/packages/13/0a/ed8b66c299e896780e4528eed4018f5b084da3b9ba4ee48328550567d866/black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, - {url = "https://files.pythonhosted.org/packages/13/25/cfa06788d0a936f2445af88f13604b5bcd5c9d050db618c718e6ebe66f74/black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, - {url = "https://files.pythonhosted.org/packages/21/14/d5a2bec5fb15f9118baab7123d344646fac0b1c6939d51c2b05259cd2d9c/black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, - {url = "https://files.pythonhosted.org/packages/24/eb/2d2d2c27cb64cfd073896f62a952a802cd83cf943a692a2f278525b57ca9/black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, - {url = "https://files.pythonhosted.org/packages/27/70/07aab2623cfd3789786f17e051487a41d5657258c7b1ef8f780512ffea9c/black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, - {url = "https://files.pythonhosted.org/packages/29/b1/b584fc863c155653963039664a592b3327b002405043b7e761b9b0212337/black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, - {url = "https://files.pythonhosted.org/packages/3c/d7/85f3d79f9e543402de2244c4d117793f262149e404ea0168841613c33e07/black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, - {url = "https://files.pythonhosted.org/packages/3f/0d/81dd4194ce7057c199d4f28e4c2a885082d9d929e7a55c514b23784f7787/black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, - {url = "https://files.pythonhosted.org/packages/49/36/15d2122f90ff1cd70f06892ebda777b650218cf84b56b5916a993dc1359a/black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, - {url = "https://files.pythonhosted.org/packages/49/d7/f3b7da6c772800f5375aeb050a3dcf682f0bbeb41d313c9c2820d0156e4e/black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, - {url = "https://files.pythonhosted.org/packages/69/49/7e1f0cf585b0d607aad3f971f95982cc4208fc77f92363d632d23021ee57/black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, - {url = "https://files.pythonhosted.org/packages/6d/b4/0f13ab7f5e364795ff82b76b0f9a4c9c50afda6f1e2feeb8b03fdd7ec57d/black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, - {url = "https://files.pythonhosted.org/packages/ad/e7/4642b7f462381799393fbad894ba4b32db00870a797f0616c197b07129a9/black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, - {url = "https://files.pythonhosted.org/packages/c0/53/42e312c17cfda5c8fc4b6b396a508218807a3fcbb963b318e49d3ddd11d5/black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, - {url = "https://files.pythonhosted.org/packages/ca/44/eb41edd3f558a6139f09eee052dead4a7a464e563b822ddf236f5a8ee286/black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, - {url = "https://files.pythonhosted.org/packages/ce/f4/2b0c6ac9e1f8584296747f66dd511898b4ebd51d6510dba118279bff53b6/black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, - {url = "https://files.pythonhosted.org/packages/d1/6e/5810b6992ed70403124c67e8b3f62858a32b35405177553f1a78ed6b6e31/black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, - {url = "https://files.pythonhosted.org/packages/d6/36/66370f5017b100225ec4950a60caeef60201a10080da57ddb24124453fba/black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, - {url = "https://files.pythonhosted.org/packages/d7/6f/d3832960a3b646b333b7f0d80d336a3c123012e9d9d5dba4a622b2b6181d/black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, - {url = "https://files.pythonhosted.org/packages/db/f4/7908f71cc71da08df1317a3619f002cbf91927fb5d3ffc7723905a2113f7/black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, - {url = "https://files.pythonhosted.org/packages/de/b4/76f152c5eb0be5471c22cd18380d31d188930377a1a57969073b89d6615d/black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, - {url = "https://files.pythonhosted.org/packages/eb/a5/17b40bfd9b607b69fa726b0b3a473d14b093dcd5191ea1a1dd664eccfee3/black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, - {url = "https://files.pythonhosted.org/packages/fd/5b/fc2d7922c1a6bb49458d424b5be71d251f2d0dc97be9534e35d171bdc653/black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, +"black 23.7.0" = [ + {url = "https://files.pythonhosted.org/packages/09/16/ec8d08d2501a39258955c16fccb55a02faa6ef44190ca9fb0b88be0f494d/black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, + {url = "https://files.pythonhosted.org/packages/10/bb/025dced0f7a2c00c59810700fbdab877b9a49cf817383133b79b0df5f0fe/black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, + {url = "https://files.pythonhosted.org/packages/13/93/b62741e817592e9dbb29935bb30daf3d7ad089dcb347e240271fe687b513/black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, + {url = "https://files.pythonhosted.org/packages/32/00/70def913a7a3f870a03e469e733c53ca016e2bf8cadf90b7bc09b98022d1/black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, + {url = "https://files.pythonhosted.org/packages/32/df/1d4ca6b76b0a077599b133b9c9dceea0b465938170043d886d4821809d40/black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, + {url = "https://files.pythonhosted.org/packages/4c/a5/e9f138d6bacc9f31906cbd5afe674ed2c48c59f5a7e46bcc466d760cd375/black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, + {url = "https://files.pythonhosted.org/packages/4d/24/06c20da91df8d0b0f67e2dd3ce0feedff0b0fa6792e24e3f83452f3c38a2/black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, + {url = "https://files.pythonhosted.org/packages/51/32/4dacd14494e60d93cbfaea023f9a82c1db998ddfa5a359afeaf5e2c11f8c/black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, + {url = "https://files.pythonhosted.org/packages/51/7a/ede3fec916bb5c00005a16e60c3be9d00b076f462ee38e7b396c5fea3411/black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, + {url = "https://files.pythonhosted.org/packages/5d/f8/76aec9b0d1eb3ac1ba3c1a143eb8fa4813b8a80a59d07fe0a8e7e914ae55/black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, + {url = "https://files.pythonhosted.org/packages/7f/1a/9e58b91b6f4ecd552de530b2309b5da32cf41e2fc116c0807c0960a96708/black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, + {url = "https://files.pythonhosted.org/packages/8e/6f/67b20e7bd900b88cd4710fb5061e79740f360677f094271d73cbcaace43c/black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, + {url = "https://files.pythonhosted.org/packages/90/65/742e1dbcced37750a5c6bd450eb2ecd2b3d8eced31918be6dc0e7c23caaf/black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, + {url = "https://files.pythonhosted.org/packages/a7/a4/4ce0eeaccfd2665b2020cf759b05868f9be5e22a4f96b789417fce8ec57c/black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, + {url = "https://files.pythonhosted.org/packages/a8/9a/eb903dd74e3dbf04981b45465b64020936317273168b4be9647c435b0f65/black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, + {url = "https://files.pythonhosted.org/packages/ca/4e/6d625c4030280d7c8b17e014ad6a6ba434acd8c6bd86d8f375d6a1235dfe/black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, + {url = "https://files.pythonhosted.org/packages/cd/89/748f5367f98f65a92cbe6b5542bb33f44fbac25f3d3d224509ac65955441/black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, + {url = "https://files.pythonhosted.org/packages/e4/17/a819f00990e8cf4e652186603ddc8d29477362da2b7717858732b6abd13d/black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, + {url = "https://files.pythonhosted.org/packages/e9/20/29d7a6614606785923edf9e8ec3ff630231992cc2fabc02eacb0d475372e/black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, + {url = "https://files.pythonhosted.org/packages/f1/7e/c8f9173e5142ff0a01e6e31b338cbda30b603a855cbb9ba7afd9552e8a36/black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, + {url = "https://files.pythonhosted.org/packages/f4/5d/d92ee301ec03a78945bd5e9d750446449832a1bf2d12919f667baec7b404/black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, + {url = "https://files.pythonhosted.org/packages/f5/07/24fc7f8381b18fb83adf619f137628da9993387e2a35616ee95cc4fccb5c/black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, ] "cachetools 5.3.1" = [ {url = "https://files.pythonhosted.org/packages/9d/8b/8e2ebf5ee26c21504de5ea2fb29cc6ae612b35fd05f959cdb641feb94ec4/cachetools-5.3.1.tar.gz", hash = "sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b"}, @@ -475,48 +472,48 @@ content_hash = "sha256:d85e84207b7cef870c53c519380c3f64e37cdfd01f4fc720977de3bab {url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, ] -"matplotlib 3.7.1" = [ - {url = "https://files.pythonhosted.org/packages/05/92/8a7449693adc4480a4777b407b44d21c0c6e3d2ace3250091fe1a89bc825/matplotlib-3.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:3ba2af245e36990facf67fde840a760128ddd71210b2ab6406e640188d69d136"}, - {url = "https://files.pythonhosted.org/packages/07/67/0d84ca088fa164ac9ad9bf1a896517ee9eeb98a27a315e1bcad619cde30c/matplotlib-3.7.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3032884084f541163f295db8a6536e0abb0db464008fadca6c98aaf84ccf4717"}, - {url = "https://files.pythonhosted.org/packages/07/76/fde990f131450f08eb06e50814b98d347b14d7916c0ec31cba0a65a9be2b/matplotlib-3.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:3d7bc90727351fb841e4d8ae620d2d86d8ed92b50473cd2b42ce9186104ecbba"}, - {url = "https://files.pythonhosted.org/packages/0e/61/255b0ab4fd319bb8274bde67eeb8b56e52c4d1b66123a6ed3de2b835d108/matplotlib-3.7.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f67bfdb83a8232cb7a92b869f9355d677bce24485c460b19d01970b64b2ed476"}, - {url = "https://files.pythonhosted.org/packages/10/94/36527e47d0719e7ae3649cc290a4d0b5faeac3453867cdf633f4b2480d87/matplotlib-3.7.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:438196cdf5dc8d39b50a45cb6e3f6274edbcf2254f85fa9b895bf85851c3a613"}, - {url = "https://files.pythonhosted.org/packages/13/0d/a3c01d8dd48957029f5ea5eac3d778fdedefaef43533597def65e29e5414/matplotlib-3.7.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99bc9e65901bb9a7ce5e7bb24af03675cbd7c70b30ac670aa263240635999a4"}, - {url = "https://files.pythonhosted.org/packages/16/23/d81f74e722eb064e726e7b6da999fd9e50de13b28e6496d67e9f09b6fe19/matplotlib-3.7.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:cf0e4f727534b7b1457898c4f4ae838af1ef87c359b76dcd5330fa31893a3ac7"}, - {url = "https://files.pythonhosted.org/packages/18/70/31f7b317e5575b590ed7227a9c3d6f42f8e8838ce7d5e763ff16440ac1d4/matplotlib-3.7.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8704726d33e9aa8a6d5215044b8d00804561971163563e6e6591f9dcf64340cc"}, - {url = "https://files.pythonhosted.org/packages/1d/24/72b0b7069d268b22c40f42d973f4b4971debd0f9ddc0fbf4753d5f0a2469/matplotlib-3.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:544764ba51900da4639c0f983b323d288f94f65f4024dc40ecb1542d74dc0500"}, - {url = "https://files.pythonhosted.org/packages/1e/5c/bae8d15f7dec470ee0269d503132678e5ce4abd1306b70b180d66ede13d5/matplotlib-3.7.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83111e6388dec67822e2534e13b243cc644c7494a4bb60584edbff91585a83c6"}, - {url = "https://files.pythonhosted.org/packages/23/7c/3e9366cf2259785de934d0bb5a7e03828e23cd722439d1c78abc4b7d89eb/matplotlib-3.7.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:770a205966d641627fd5cf9d3cb4b6280a716522cd36b8b284a8eb1581310f61"}, - {url = "https://files.pythonhosted.org/packages/34/b3/c81bbb3de820e0eaba4d7d41b9df34ffdc3336159de5bb6c959cd2028670/matplotlib-3.7.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b867e2f952ed592237a1828f027d332d8ee219ad722345b79a001f49df0936eb"}, - {url = "https://files.pythonhosted.org/packages/35/a8/eb84f46e133fc0be5d50c3e1bec0aaa18a58bb53fc9ea96797289ffb2cd2/matplotlib-3.7.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a2cb34336110e0ed8bb4f650e817eed61fa064acbefeb3591f1b33e3a84fd96"}, - {url = "https://files.pythonhosted.org/packages/3a/4e/83499803b641c40e33c118b461a7c110bfa8cc6b3be10a2dc174232522dd/matplotlib-3.7.1-cp311-cp311-win32.whl", hash = "sha256:fbdeeb58c0cf0595efe89c05c224e0a502d1aa6a8696e68a73c3efc6bc354304"}, - {url = "https://files.pythonhosted.org/packages/4d/71/a0d28c6123773075f056ff2ce7b2a16a19a4ff2982f0de0f285c9866c420/matplotlib-3.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8bf26ade3ff0f27668989d98c8435ce9327d24cffb7f07d24ef609e33d582439"}, - {url = "https://files.pythonhosted.org/packages/51/3e/2e266434cf7aa82ab5d860b774a1ece49debffa3f5c32f7c6e305f0f5728/matplotlib-3.7.1-cp38-cp38-win32.whl", hash = "sha256:7c9a4b2da6fac77bcc41b1ea95fadb314e92508bf5493ceff058e727e7ecf5b0"}, - {url = "https://files.pythonhosted.org/packages/51/d8/ba69105b4b72aace5d3501af1b0886b248fa5363519df04dc17577578bab/matplotlib-3.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a867bf73a7eb808ef2afbca03bcdb785dae09595fbe550e1bab0cd023eba3de0"}, - {url = "https://files.pythonhosted.org/packages/5c/b0/050bcf86c57255066915eb805d36409e2e093a07d4615249b07aa2530ef5/matplotlib-3.7.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:6eb88d87cb2c49af00d3bbc33a003f89fd9f78d318848da029383bfc08ecfbfb"}, - {url = "https://files.pythonhosted.org/packages/5d/22/f55638bea4af17edf23e1c919ad5d256141bbeec0196c450be9785f1dcb6/matplotlib-3.7.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4cf327e98ecf08fcbb82685acaf1939d3338548620ab8dfa02828706402c34de"}, - {url = "https://files.pythonhosted.org/packages/5d/7e/0647f19705d819d2249df96625d83ff5de2e913a247610b753c504b7bfd0/matplotlib-3.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2bf092f9210e105f414a043b92af583c98f50050559616930d884387d0772aba"}, - {url = "https://files.pythonhosted.org/packages/62/6d/3817522ca223796703b68ffd38577582f2dc7a0c0dd410d1803e36b5e1db/matplotlib-3.7.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:95cbc13c1fc6844ab8812a525bbc237fa1470863ff3dace7352e910519e194b1"}, - {url = "https://files.pythonhosted.org/packages/6c/70/5f8b981680fc0bdb85f0dd00174e41f98d4cdb641921295822c8e14272fe/matplotlib-3.7.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:28506a03bd7f3fe59cd3cd4ceb2a8d8a2b1db41afede01f66c42561b9be7b4b7"}, - {url = "https://files.pythonhosted.org/packages/80/c0/1d29eafc057e516ffc1ba07da2054926f219c44ad4ea5df57ff97825182c/matplotlib-3.7.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:81a6b377ea444336538638d31fdb39af6be1a043ca5e343fe18d0f17e098770b"}, - {url = "https://files.pythonhosted.org/packages/81/f7/1c9145e24195723da3cb668637b98b6016be4692b335ba543058a7297c9e/matplotlib-3.7.1-cp39-cp39-win32.whl", hash = "sha256:4f99e1b234c30c1e9714610eb0c6d2f11809c9c78c984a613ae539ea2ad2eb4b"}, - {url = "https://files.pythonhosted.org/packages/83/3e/08d551274d660cd38af04b14366725c195f18ad0bd359e192ecf3ec2f2bb/matplotlib-3.7.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:97cc368a7268141afb5690760921765ed34867ffb9655dd325ed207af85c7529"}, - {url = "https://files.pythonhosted.org/packages/86/2b/a04f22015a03025a8c9c0363c4ecfd89eb45fc3af545ff838e02ac58b39d/matplotlib-3.7.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:08308bae9e91aca1ec6fd6dda66237eef9f6294ddb17f0d0b3c863169bf82353"}, - {url = "https://files.pythonhosted.org/packages/89/f3/84a9a6613ab0d89931d785f13fa2606e03f07252875acc8ebf5b676fa3c5/matplotlib-3.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb7d248c34a341cd4c31a06fd34d64306624c8cd8d0def7abb08792a5abfd556"}, - {url = "https://files.pythonhosted.org/packages/8a/d3/35c62c9f64ddef5f25763580a10cb1ff4a19dc1a2bf940ad06dbb10b248d/matplotlib-3.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d94989191de3fcc4e002f93f7f1be5da476385dde410ddafbb70686acf00ea"}, - {url = "https://files.pythonhosted.org/packages/91/ae/410dca50b2b0b4d48bfaa41a20d7344078ac63a7178d3b5716b1014c90b9/matplotlib-3.7.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:21e9cff1a58d42e74d01153360de92b326708fb205250150018a52c70f43c290"}, - {url = "https://files.pythonhosted.org/packages/92/01/2c04d328db6955d77f8f60c17068dde8aa66f153b2c599ca03c2cb0d5567/matplotlib-3.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:14645aad967684e92fc349493fa10c08a6da514b3d03a5931a1bac26e6792bd1"}, - {url = "https://files.pythonhosted.org/packages/9f/77/0cd22f92f7103383cb1ce3b3efc77411b9cc3a495242c8f2a623b498f586/matplotlib-3.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f883a22a56a84dba3b588696a2b8a1ab0d2c3d41be53264115c71b0a942d8fdb"}, - {url = "https://files.pythonhosted.org/packages/a8/14/83b722ae5bec25cd1b44067d2165952aa0943af287ea06f2e1e594220805/matplotlib-3.7.1-cp310-cp310-win32.whl", hash = "sha256:ce463ce590f3825b52e9fe5c19a3c6a69fd7675a39d589e8b5fbe772272b3a24"}, - {url = "https://files.pythonhosted.org/packages/b7/65/d6e00376dbdb6c227d79a2d6ec32f66cfb163f0cd924090e3133a4f85a11/matplotlib-3.7.1.tar.gz", hash = "sha256:7b73305f25eab4541bd7ee0b96d87e53ae9c9f1823be5659b806cd85786fe882"}, - {url = "https://files.pythonhosted.org/packages/b7/ed/32d00261ac6067b13af9181b2450d30599875ab61807defa85c05a28432a/matplotlib-3.7.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:57bfb8c8ea253be947ccb2bc2d1bb3862c2bccc662ad1b4626e1f5e004557042"}, - {url = "https://files.pythonhosted.org/packages/bc/22/52dd9b0f8da380309ceb4c5e6a9018417b56ad3b56bfd18fe0e1d1310541/matplotlib-3.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:617f14ae9d53292ece33f45cba8503494ee199a75b44de7717964f70637a36aa"}, - {url = "https://files.pythonhosted.org/packages/bd/5d/a9083be15f9bed89c1c5897473eae6dd1bab4acbcfb82fdae417149674d0/matplotlib-3.7.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:def58098f96a05f90af7e92fd127d21a287068202aa43b2a93476170ebd99e87"}, - {url = "https://files.pythonhosted.org/packages/cf/2c/41b330eeb47806abc19c1a4ab22821cb5a2be2cabe34c37f0d8483ae0e26/matplotlib-3.7.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d4725d70b7c03e082bbb8a34639ede17f333d7247f56caceb3801cb6ff703d"}, - {url = "https://files.pythonhosted.org/packages/e0/2e/a9fc4c317bc8cc679d344dd881b97f67580b38e6eedc645c3623d6c5d139/matplotlib-3.7.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89768d84187f31717349c6bfadc0e0d8c321e8eb34522acec8a67b1236a66332"}, - {url = "https://files.pythonhosted.org/packages/e8/5a/2661b38ebd4b1d58f335be7e8150af0a7eb94d13bf7a6563e7c49ed40c4d/matplotlib-3.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c587963b85ce41e0a8af53b9b2de8dddbf5ece4c34553f7bd9d066148dc719c"}, - {url = "https://files.pythonhosted.org/packages/f3/99/7010ae81984908cc655b7d24145aeed2784614957ed7f0cb5a72b17a63d3/matplotlib-3.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:46a561d23b91f30bccfd25429c3c706afe7d73a5cc64ef2dfaf2b2ac47c1a5dc"}, - {url = "https://files.pythonhosted.org/packages/fb/8c/391e3c105edb7e193bb163ed48988135228d0b5ce3143e1cbec2350e23c8/matplotlib-3.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:c0bd19c72ae53e6ab979f0ac6a3fafceb02d2ecafa023c5cca47acd934d10be7"}, +"matplotlib 3.7.2" = [ + {url = "https://files.pythonhosted.org/packages/1d/57/888776de79e1c2e787368ecbe63e3e57dbec984a5c83220e44c15fefe226/matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"}, + {url = "https://files.pythonhosted.org/packages/40/28/2cadcff6fe0b7498726d9efe259c0d85625dda59932ec04fb1de811b0968/matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"}, + {url = "https://files.pythonhosted.org/packages/47/57/fe4ebc5133923500e8c6965e6691746568142549f18b87346889c5480852/matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"}, + {url = "https://files.pythonhosted.org/packages/47/b9/6c0daa9b953a80b4e6933bf6a11a2d0633f257e84ee5995c5fd35de564c9/matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"}, + {url = "https://files.pythonhosted.org/packages/4d/9c/65830d4a56c47f5283eaa244dc1228c5da9c844a9f999ebcc2e69bf6cc65/matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"}, + {url = "https://files.pythonhosted.org/packages/4f/d7/3303f11188122f66c940056f162d030992e7fbc9c702869bab163e85156b/matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"}, + {url = "https://files.pythonhosted.org/packages/51/93/61bc85bda07e1242b2a4ab1bbcee0c3ea9429c6c15ef4a89613e685474c3/matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"}, + {url = "https://files.pythonhosted.org/packages/54/6d/78dd357b35a9c94a56c51a34c123460313e3bdf2e454ce4274ac67b9a5e0/matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"}, + {url = "https://files.pythonhosted.org/packages/54/e2/ac7a37a36f6ab1f83896cfd3d4832a0082e4106de10087a5afe29da2e990/matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"}, + {url = "https://files.pythonhosted.org/packages/5d/23/5efd23e54a6992df25b656956576781e8c8064acc570c0f6f3dbf0a573f0/matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"}, + {url = "https://files.pythonhosted.org/packages/5d/f1/1f2dc9a7e380b05f13b16d7af451664ee862a7ce93e887e55e3fc316c933/matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"}, + {url = "https://files.pythonhosted.org/packages/61/4d/f57df318c3e9dc1167271f08f7f058dec0f575a469edccf873cd16dcfc8a/matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"}, + {url = "https://files.pythonhosted.org/packages/64/e1/e7ee2ac522b66aed3022da0ab33b90e7d7f58aa17adbfaf123247598a0af/matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"}, + {url = "https://files.pythonhosted.org/packages/6d/f8/ff4acac6ea3f896146fd2a9f76dafb7c36973f2a329cae1d60a7c7252395/matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"}, + {url = "https://files.pythonhosted.org/packages/72/7d/2ad1b94106f8b1971d1eff0ebb97a81d980c448732a3e624bba281bd274d/matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"}, + {url = "https://files.pythonhosted.org/packages/7e/2c/1e25437f4419f2828bbd213be42c8fd23a3b795c5c4bb776987d177fc615/matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"}, + {url = "https://files.pythonhosted.org/packages/80/99/6cb77705e4801b4483410b9b917790fdc2da311ec8dd1ed8c9e90320c0e1/matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"}, + {url = "https://files.pythonhosted.org/packages/83/ed/eeaa45dadeb1614761195cc7931823d6fee50645299d02b348f48bbeea1e/matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"}, + {url = "https://files.pythonhosted.org/packages/85/44/2b91e75fd133393e76455bb3ac44b9b885668264eafb0f9510f6aeb41fb5/matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"}, + {url = "https://files.pythonhosted.org/packages/85/7c/7ad0e30d26afc8913248e4aa71cc360944d3ccff38ed78f6a4578bd9ff73/matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"}, + {url = "https://files.pythonhosted.org/packages/85/9d/45157aebc2e78225106cc21f195f38d9fcc2c6bf5a947309406cfbcbef51/matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"}, + {url = "https://files.pythonhosted.org/packages/88/4c/a7779dd6cf666ce115f9da4f6cca94f5f6fa31c5354e9efa1da6269c0457/matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"}, + {url = "https://files.pythonhosted.org/packages/88/a1/87831b97514680828bfbac6054c38bda114ef8acd58150309467e9190cb7/matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"}, + {url = "https://files.pythonhosted.org/packages/8d/22/719f4fff33b13b0708711fb52ca3fc44617a26728e0e023358288d5197ae/matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"}, + {url = "https://files.pythonhosted.org/packages/99/e2/87294a9455c6a6b9d8f69d046032c2ef04220094b590474b3b51526082ab/matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"}, + {url = "https://files.pythonhosted.org/packages/a3/e5/c9cdc737ea2256285dc1b28e8ecbf649c716cfc7b1ee12a8be6d4cf1feb7/matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"}, + {url = "https://files.pythonhosted.org/packages/ab/43/734eddeb4636775467287e2626ffe64d7a94f432ed829c60f687ebd0b1d4/matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"}, + {url = "https://files.pythonhosted.org/packages/b2/b6/c6596fbc30899e6da31450053054d7da61a21a3f510544fb7cb7658a3de3/matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"}, + {url = "https://files.pythonhosted.org/packages/b4/c2/f74e0deb26379aead0956a6ecf9acd4587debba0c7abe4bd8fe53fe04ec2/matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"}, + {url = "https://files.pythonhosted.org/packages/c2/da/a5622266952ab05dc3995d77689cba600e49ea9d6c51d469c077695cb719/matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"}, + {url = "https://files.pythonhosted.org/packages/c9/46/6cbaf20f5bd0e7c1d204b45b853c2cd317b303fada90245f2825ecca47de/matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"}, + {url = "https://files.pythonhosted.org/packages/cd/e6/1843e183dd56287e8c33cd163c245b551e56b82ce8d54049e0810166be30/matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"}, + {url = "https://files.pythonhosted.org/packages/d0/39/4c4fb38ec2356bcbc9017a5421623aec69aacde110e4e76d34d0a43702f0/matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"}, + {url = "https://files.pythonhosted.org/packages/d8/76/ed92bfa302782be7cf6d9ac4338cd2a1a3c131892fc04bddf6cf07adcb01/matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"}, + {url = "https://files.pythonhosted.org/packages/e0/a9/afd0e7b98e4b855c884b737256c53e51c0126a4a40e8350228eb544644fb/matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"}, + {url = "https://files.pythonhosted.org/packages/e5/59/b859fa2539b4121b016ea85758188203522fc12b0711de8b247cfec3cdac/matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"}, + {url = "https://files.pythonhosted.org/packages/f3/3c/b6f83a7e516aa4058b3878107390b6d9dfb24491a5018937886b54008e0b/matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"}, + {url = "https://files.pythonhosted.org/packages/f4/33/41a775c34ec6ae0d84c188c09da3fe3a268c1cd28045e8013aeda346b8b9/matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"}, + {url = "https://files.pythonhosted.org/packages/f6/22/9c31044ff7339c63727a135872e5cb59564f11625372a81c3eebf148f4af/matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"}, + {url = "https://files.pythonhosted.org/packages/f6/e4/9621a1ec9312ca20f18c045690757f2276fb980d1b2beb23a7ee28d914db/matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"}, + {url = "https://files.pythonhosted.org/packages/ff/1f/2b83c7acf453318a80dc619e99fc30a663b2c1fb18be3d358a96addfecd9/matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"}, ] "mdurl 0.1.2" = [ {url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, @@ -526,32 +523,32 @@ content_hash = "sha256:d85e84207b7cef870c53c519380c3f64e37cdfd01f4fc720977de3bab {url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -"numpy 1.25.0" = [ - {url = "https://files.pythonhosted.org/packages/13/a0/bd219e125915e1d5706a5d00b87cd93932d6a204d976aea09fa0f36af5a1/numpy-1.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0dc071017bc00abb7d7201bac06fa80333c6314477b3d10b52b58fa6a6e38f6"}, - {url = "https://files.pythonhosted.org/packages/50/4b/2246882e9c89e8da081296bef4539ab1d44bf97f757931ddaf5f7d0a3b58/numpy-1.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:26815c6c8498dc49d81faa76d61078c4f9f0859ce7817919021b9eba72b425e3"}, - {url = "https://files.pythonhosted.org/packages/52/68/ce0a665654fbc26a00ba9dfbd98a6f749246576bbc826710676ca9f67a1c/numpy-1.25.0-cp39-cp39-win32.whl", hash = "sha256:7412125b4f18aeddca2ecd7219ea2d2708f697943e6f624be41aa5f8a9852cc4"}, - {url = "https://files.pythonhosted.org/packages/68/44/1ff079e62f44fc6d17aea45ec6a7008c033c9a59972644c320c4fda95a49/numpy-1.25.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5177310ac2e63d6603f659fadc1e7bab33dd5a8db4e0596df34214eeab0fee3b"}, - {url = "https://files.pythonhosted.org/packages/75/74/7eec4db7eea3796fe6f47bc358c24447fc66a080ac2fd35cbe4a3cd8d17b/numpy-1.25.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85cdae87d8c136fd4da4dad1e48064d700f63e923d5af6c8c782ac0df8044542"}, - {url = "https://files.pythonhosted.org/packages/76/72/d9e66a7bef82261aff26c71b8ac8b13fa2ffa965e046be958f949ca3388f/numpy-1.25.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cc3fda2b36482891db1060f00f881c77f9423eead4c3579629940a3e12095fe8"}, - {url = "https://files.pythonhosted.org/packages/77/03/79b0bfc6e9dcd5eabbb17a714a2480ad3f932063eb8b39f6116ac207d5e3/numpy-1.25.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aedd08f15d3045a4e9c648f1e04daca2ab1044256959f1f95aafeeb3d794c16"}, - {url = "https://files.pythonhosted.org/packages/8c/00/a65518f58b9bbba597cd757a765d7a34fea3d8fd089a8ecc7f6eb4e4f42d/numpy-1.25.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecc68f11404930e9c7ecfc937aa423e1e50158317bf67ca91736a9864eae0232"}, - {url = "https://files.pythonhosted.org/packages/8e/de/a6cddb5b3b2ffd03bc0061dcb7c0edeaff2d10460eed8e0e9a57341ce455/numpy-1.25.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0ac6edfb35d2a99aaf102b509c8e9319c499ebd4978df4971b94419a116d0790"}, - {url = "https://files.pythonhosted.org/packages/a5/c7/586bc658351595f252dd6fa31a14ca28ca7de7d93171f933b1c193e7e32c/numpy-1.25.0-cp310-cp310-win32.whl", hash = "sha256:d76a84998c51b8b68b40448ddd02bd1081bb33abcdc28beee6cd284fe11036c6"}, - {url = "https://files.pythonhosted.org/packages/a7/71/8cadc39a58fc18a91ad135c3a33b6a6a7c0ccf00adb4263d6f2aebf8124d/numpy-1.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8aa130c3042052d656751df5e81f6d61edff3e289b5994edcf77f54118a8d9f4"}, - {url = "https://files.pythonhosted.org/packages/a8/a5/dded2b52d4a460f265973f2aaedc5ea82814d471241e5d17599506c4ee0e/numpy-1.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d183b5c58513f74225c376643234c369468e02947b47942eacbb23c1671f25d"}, - {url = "https://files.pythonhosted.org/packages/bb/b9/0f7a1d48d5c65c7a2cc8d5de119318a254351a0146e696855ade26615455/numpy-1.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c69fe5f05eea336b7a740e114dec995e2f927003c30702d896892403df6dbf0"}, - {url = "https://files.pythonhosted.org/packages/c8/7c/87cf5dc663803120901302db2494e625d762e19060b390d925e3e8666b18/numpy-1.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e3f2b96e3b63c978bc29daaa3700c028fe3f049ea3031b58aa33fe2a5809d24"}, - {url = "https://files.pythonhosted.org/packages/d0/62/7c85c27e4277b142a91023bfb69ba27f1783777d31f5e920b314e1a92f69/numpy-1.25.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7cd981ccc0afe49b9883f14761bb57c964df71124dcd155b0cba2b591f0d64b9"}, - {url = "https://files.pythonhosted.org/packages/d0/b2/fe774844d1857804cc884bba67bec38f649c99d0dc1ee7cbbf1da601357c/numpy-1.25.0.tar.gz", hash = "sha256:f1accae9a28dc3cda46a91de86acf69de0d1b5f4edd44a9b0c3ceb8036dfff19"}, - {url = "https://files.pythonhosted.org/packages/d2/b0/ce6c0056f057e681b0b9f78900e122715389f865047c25fc2f37bfe2f8fe/numpy-1.25.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa48bebfb41f93043a796128854b84407d4df730d3fb6e5dc36402f5cd594c0"}, - {url = "https://files.pythonhosted.org/packages/de/8b/b2d73b913be92056b1f77b0b9d184d93f368353540adf91e699a10a2effb/numpy-1.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:b76aa836a952059d70a2788a2d98cb2a533ccd46222558b6970348939e55fc24"}, - {url = "https://files.pythonhosted.org/packages/e3/51/524ba2b98e083b59dc287011adc6829778c496998aa329715a6a13ae4735/numpy-1.25.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b1b90860bf7d8a8c313b372d4f27343a54f415b20fb69dd601b7efe1029c91e"}, - {url = "https://files.pythonhosted.org/packages/e8/bd/937ffc7345985456c963089418c4c7efdb2ca3af36624c5ea60a07d99bcf/numpy-1.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c7211d7920b97aeca7b3773a6783492b5b93baba39e7c36054f6e749fc7490c"}, - {url = "https://files.pythonhosted.org/packages/ed/f6/1ce8d0bdcf926a5d94ae2a793eee4364c76ba2d1a5b73ee9de9aebc3a0e0/numpy-1.25.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6b267f349a99d3908b56645eebf340cb58f01bd1e773b4eea1a905b3f0e4208"}, - {url = "https://files.pythonhosted.org/packages/ef/29/a2503fed1bb38902e789f3e73259d760911fb7b51420896716502c727aa1/numpy-1.25.0-cp311-cp311-win32.whl", hash = "sha256:95367ccd88c07af21b379be1725b5322362bb83679d36691f124a16357390153"}, - {url = "https://files.pythonhosted.org/packages/f4/73/08500367cf69634970c87d11bcc82dc0daf4d9554a3e5d4a3750f26c25b7/numpy-1.25.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b792164e539d99d93e4e5e09ae10f8cbe5466de7d759fc155e075237e0c274e4"}, - {url = "https://files.pythonhosted.org/packages/f6/ae/546c18cad7525242d87def9ee1cba2e407028044f79c023ea8b2a11397d2/numpy-1.25.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e559c6afbca484072a98a51b6fa466aae785cfe89b69e8b856c3191bc8872a82"}, - {url = "https://files.pythonhosted.org/packages/fa/9f/9023a2135a86a80369c942670ef23c2c838aee3408f982e3b9bcaf9ffe61/numpy-1.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6c284907e37f5e04d2412950960894b143a648dea3f79290757eb878b91acbd1"}, +"numpy 1.25.1" = [ + {url = "https://files.pythonhosted.org/packages/06/23/883340d4a8ff93ab24beb5a25c53f5999e0016c20ed2171853bbd2cdf9f4/numpy-1.25.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3d7abcdd85aea3e6cdddb59af2350c7ab1ed764397f8eec97a038ad244d2d105"}, + {url = "https://files.pythonhosted.org/packages/0a/54/370ec143539de0dc09c3024b4fea99e76e3051bd6ad199ccf1e5b6bc05b7/numpy-1.25.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d412c1697c3853c6fc3cb9751b4915859c7afe6a277c2bf00acf287d56c4e625"}, + {url = "https://files.pythonhosted.org/packages/1b/cd/9e8313ffd849626c836fffd7881296a74f53a7739bd9ce7a6e22b1fc843b/numpy-1.25.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d736b75c3f2cb96843a5c7f8d8ccc414768d34b0a75f466c05f3a739b406f10b"}, + {url = "https://files.pythonhosted.org/packages/21/9c/1a7d658112aed97be36dfd93cc7362ca6c33598615988e6d836fa0a80f89/numpy-1.25.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20e1266411120a4f16fad8efa8e0454d21d00b8c7cee5b5ccad7565d95eb42dd"}, + {url = "https://files.pythonhosted.org/packages/28/65/46e9c57b034c63f67d4a76fe335c0204e80d4722e94939de684af0456ef0/numpy-1.25.1-cp311-cp311-win32.whl", hash = "sha256:791f409064d0a69dd20579345d852c59822c6aa087f23b07b1b4e28ff5880fcb"}, + {url = "https://files.pythonhosted.org/packages/28/68/a4594268ecddf860de11fa541ee789e9c2d23b3854f9f04d308960768c60/numpy-1.25.1-cp310-cp310-win32.whl", hash = "sha256:fd67b306320dcadea700a8f79b9e671e607f8696e98ec255915c0c6d6b818503"}, + {url = "https://files.pythonhosted.org/packages/2f/2a/34fe0b64e78347f4ea128868df0034a97e0f92b476f62947b0976caba820/numpy-1.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:c40571fe966393b212689aa17e32ed905924120737194b5d5c1b20b9ed0fb171"}, + {url = "https://files.pythonhosted.org/packages/3c/81/90d13a812268943226a9ca8d4967343f9e273a5d9a1063f8a99736816eba/numpy-1.25.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a90725800caeaa160732d6b31f3f843ebd45d6b5f3eec9e8cc287e30f2805bf"}, + {url = "https://files.pythonhosted.org/packages/48/73/df07644e8fa1127a7985db70cf1d07123004e2dd7a3cf33e8b83297a775b/numpy-1.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e8f6049c4878cb16960fbbfb22105e49d13d752d4d8371b55110941fb3b17800"}, + {url = "https://files.pythonhosted.org/packages/55/ee/a9cb689bab52cb617094148a2db7f87f89fb390682392545e8751a9cf06b/numpy-1.25.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38eb6548bb91c421261b4805dc44def9ca1a6eef6444ce35ad1669c0f1a3fc5d"}, + {url = "https://files.pythonhosted.org/packages/7c/be/76ae69de42c60e9d14252df2191db298e955223853dff6a77c9d1e01cd71/numpy-1.25.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41a56b70e8139884eccb2f733c2f7378af06c82304959e174f8e7370af112e09"}, + {url = "https://files.pythonhosted.org/packages/83/b8/76d402c0c09aa08befa84f7a55c714ba4e2d9974134e8881aa42ac46abd5/numpy-1.25.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:35a9527c977b924042170a0887de727cd84ff179e478481404c5dc66b4170009"}, + {url = "https://files.pythonhosted.org/packages/86/c7/f92afdefa2bccdf0bc357321a931adafb1a999bc84f8877a6ed786a69ccc/numpy-1.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:1d5d3c68e443c90b38fdf8ef40e60e2538a27548b39b12b73132456847f4b631"}, + {url = "https://files.pythonhosted.org/packages/8d/07/cab4129005dba3f170dd1a2cfa312fc71100f0e26b91f7fc659b6b5abbdc/numpy-1.25.1-cp310-cp310-win_amd64.whl", hash = "sha256:c1516db588987450b85595586605742879e50dcce923e8973f79529651545b57"}, + {url = "https://files.pythonhosted.org/packages/94/83/2473c27e3f52339d1278d7b02245211d1ecf9c5eb2d97cc17370bf59ef10/numpy-1.25.1-cp39-cp39-win32.whl", hash = "sha256:247d3ffdd7775bdf191f848be8d49100495114c82c2bd134e8d5d075fb386a1c"}, + {url = "https://files.pythonhosted.org/packages/99/08/7a793f0ad404a0d9f03debeb82cf9039b8ce60d5a6631b35f4991f6fc93a/numpy-1.25.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f76aebc3358ade9eacf9bc2bb8ae589863a4f911611694103af05346637df1b7"}, + {url = "https://files.pythonhosted.org/packages/b8/66/d74ebeff4fbd678d19002f7be03c3f9ab57604e4606d67d9b18431250cc2/numpy-1.25.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:012097b5b0d00a11070e8f2e261128c44157a8689f7dedcf35576e525893f4fe"}, + {url = "https://files.pythonhosted.org/packages/bd/8a/7eccc0d8b54c85a0b210a72c3f8be71eecc7db1bf62dcd9275a911282a5a/numpy-1.25.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d3fe3dd0506a28493d82dc3cf254be8cd0d26f4008a417385cbf1ae95b54004"}, + {url = "https://files.pythonhosted.org/packages/cf/7a/f68d1d658a0e68084097beb212fa9356fee7eabff8b57231cc4acb555b12/numpy-1.25.1.tar.gz", hash = "sha256:9a3a9f3a61480cc086117b426a8bd86869c213fc4072e606f01c4e4b66eb92bf"}, + {url = "https://files.pythonhosted.org/packages/d0/55/559e6f455a066e12058330377259a106b7fefa41c15dbdb1b71070cec429/numpy-1.25.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c6c9261d21e617c6dc5eacba35cb68ec36bb72adcff0dee63f8fbc899362588"}, + {url = "https://files.pythonhosted.org/packages/dd/68/ee92adfe1cadfc36f5bb7301eae5c8ad8138ec4dae83d68014f2a7f3709f/numpy-1.25.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a180429394f81c7933634ae49b37b472d343cccb5bb0c4a575ac8bbc433722f"}, + {url = "https://files.pythonhosted.org/packages/e3/7e/0b072c21f4feefb2d89600956af307db29fb7df695cbe6e145de91643155/numpy-1.25.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6b82655dd8efeea69dbf85d00fca40013d7f503212bc5259056244961268b66e"}, + {url = "https://files.pythonhosted.org/packages/e9/ce/27f1961d50170ab38fd739263465437fb193404dc8fac7dd0b3bb146c95a/numpy-1.25.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0def91f8af6ec4bb94c370e38c575855bf1d0be8a8fbfba42ef9c073faf2cf19"}, + {url = "https://files.pythonhosted.org/packages/f0/5a/9b7b7bae29f9f5f8a976607cd30139c1fec9076c0e65ea918d3400924acf/numpy-1.25.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5154b1a25ec796b1aee12ac1b22f414f94752c5f94832f14d8d6c9ac40bcca6"}, + {url = "https://files.pythonhosted.org/packages/fa/07/c6980120967a9fc76138eddd583d6ac47dd072922d6f66d7d502f6f9a964/numpy-1.25.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:77d339465dff3eb33c701430bcb9c325b60354698340229e1dff97745e6b3efa"}, ] "packaging 23.1" = [ {url = "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, @@ -587,6 +584,7 @@ content_hash = "sha256:d85e84207b7cef870c53c519380c3f64e37cdfd01f4fc720977de3bab {url = "https://files.pythonhosted.org/packages/60/34/c90bacb4a72ead5c78e4d8291e0d3bb88cc3def3c76f059e9a8502fc421e/Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, {url = "https://files.pythonhosted.org/packages/62/66/6b011b44193fe724f10949ae59ad6e045811f9fdc7ee994687eec44a54c5/Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, {url = "https://files.pythonhosted.org/packages/66/d4/054e491f0880bf0119ee79cdc03264e01d5732e06c454da8c69b83a7c8f2/Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, + {url = "https://files.pythonhosted.org/packages/6a/33/c278084a811d7a7a17c8dd14cb261248fdd0265263760fb753a5a719241e/Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, {url = "https://files.pythonhosted.org/packages/6e/4b/350373454133ceef9b14ec804781d9c8e4e10ac112f85c55285140315a67/Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, {url = "https://files.pythonhosted.org/packages/72/17/6c1e6b0f78d21838844318057b7a939ab8a8d92deeb51d22563202b2db64/Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, {url = "https://files.pythonhosted.org/packages/73/26/75fd7c1adc40bbdcbebc1adc120388d581e1d98a106257369a9bf8c44865/Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, @@ -595,6 +593,7 @@ content_hash = "sha256:d85e84207b7cef870c53c519380c3f64e37cdfd01f4fc720977de3bab {url = "https://files.pythonhosted.org/packages/79/53/3a7277ae95bfe86b8b4db0ed1d08c4924aa2dfbfe51b8fe0e310b160a9c6/Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, {url = "https://files.pythonhosted.org/packages/7a/54/f6a14d95cba8ff082c550d836c9e5c23f1641d2ac291c23efe0494219b8c/Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, {url = "https://files.pythonhosted.org/packages/7b/c9/08de9a629ce7cdeaea0ddca716e9efcd1844b2650f5b9dd8ec5609e40ffe/Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, + {url = "https://files.pythonhosted.org/packages/83/c0/aaa4f7f9f0ed854d8b519739392ed17ee1aaaa352fd037646e97634a6bdb/Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, {url = "https://files.pythonhosted.org/packages/8a/ec/3e874bc51ccebf03f1ca4ea1e177569c0d7b37ee5a16ff497a73ed5800e0/Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, {url = "https://files.pythonhosted.org/packages/8b/b3/d7b6ee16358d829ca482c74a96e2b9079bf33f8d7d37d16f8ebb19ddf5a4/Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, {url = "https://files.pythonhosted.org/packages/8f/b8/1bf1012eee3059d150194d1fab148f553f3df42cf412e4e6656c772afad9/Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, @@ -732,9 +731,9 @@ content_hash = "sha256:d85e84207b7cef870c53c519380c3f64e37cdfd01f4fc720977de3bab {url = "https://files.pythonhosted.org/packages/34/a7/37c8d68532ba71549db4212cb036dbd6161b40e463aba336770e80c72f84/Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, {url = "https://files.pythonhosted.org/packages/89/6b/2114e54b290824197006e41be3f9bbe1a26e9c39d1f5fa20a6d62945a0b3/Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, ] -"pyparsing 3.1.0" = [ - {url = "https://files.pythonhosted.org/packages/4f/13/28e88033cab976721512e7741000fb0635fa078045e530a91abb25aea0c0/pyparsing-3.1.0.tar.gz", hash = "sha256:edb662d6fe322d6e990b1594b5feaeadf806803359e3d4d42f11e295e588f0ea"}, - {url = "https://files.pythonhosted.org/packages/a4/24/6ae4c9c45cf99d96b06b5d99e25526c060303171fb0aea9da2bfd7dbde93/pyparsing-3.1.0-py3-none-any.whl", hash = "sha256:d554a96d1a7d3ddaf7183104485bc19fd80543ad6ac5bdb6426719d766fb06c1"}, +"pyparsing 3.0.9" = [ + {url = "https://files.pythonhosted.org/packages/6c/10/a7d0fa5baea8fe7b50f448ab742f26f52b80bfca85ac2be9d35cdd9a3246/pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {url = "https://files.pythonhosted.org/packages/71/22/207523d16464c40a0310d2d4d8926daffa00ac1f5b1576170a32db749636/pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] "python-dateutil 2.8.2" = [ {url = "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, diff --git a/pyproject.toml b/pyproject.toml index 2701a7a5..ba7f45bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ "RUF", # Ruff-specific "SIM", # flake8-simplify "T20", # flake8-print + # "TCH", # flake8-type-checking "UP", # pyupgrade "YTT", # flake8-2020 "EXE", # flake8-executable