From 03abcd1417e2269cb342a1d9fba73d53de590350 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sat, 24 Aug 2024 08:45:55 +0200 Subject: [PATCH] chore(ruff): #80 apply preliminary rules (#86) * chore(ruff): #80 add to pre-commit * chore(ruff): #80 automatic fixes * chore(typo): #80 * chore(pre-commit): #80 add to pyproject.toml * chore(ruff): #80 comment by @emptymalei https://github.com/kausalflow/hamilflow/pull/86#discussion_r1725718123 --- .pre-commit-config.yaml | 17 ++- docs/tutorials/harmonic_oscillator.py | 10 +- docs/tutorials/kepler_problem.py | 4 - docs/tutorials/pendulum.py | 5 +- hamilflow/maths/trigonometrics.py | 1 - hamilflow/models/brownian_motion.py | 2 +- hamilflow/models/free_particle.py | 3 +- hamilflow/models/harmonic_oscillator.py | 14 +-- hamilflow/models/harmonic_oscillator_chain.py | 28 +++-- hamilflow/models/kepler_problem/dynamics.py | 21 ++-- hamilflow/models/kepler_problem/model.py | 8 +- hamilflow/models/kepler_problem/numerics.py | 10 +- hamilflow/models/pendulum.py | 3 +- poetry.lock | 105 +++++++++++++++++- pyproject.toml | 18 +++ tests/models/kepler_problem/conftest.py | 5 +- tests/models/kepler_problem/test_dynamics.py | 7 +- tests/models/kepler_problem/test_model.py | 5 +- tests/models/kepler_problem/test_numerics.py | 2 +- tests/models/test_brownian_motion.py | 6 +- tests/models/test_free_particle.py | 12 +- tests/models/test_harmonic_oscillator.py | 17 ++- .../models/test_harmonic_oscillator_chain.py | 28 +++-- tests/models/test_pendulum.py | 10 +- 24 files changed, 259 insertions(+), 82 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d4d8e64..69ece53 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,17 +9,22 @@ repos: - id: end-of-file-fixer - id: requirements-txt-fixer - id: trailing-whitespace + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.6.1 + hooks: + # Run the linter. + - id: ruff + args: + - --fix + - --exit-non-zero-on-fix + # Run the formatter. + - id: ruff-format - repo: https://github.com/ambv/black rev: 24.4.2 hooks: - id: black language: python - - repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - name: isort (python) - args: ["--multi-line", "3", "--profile", "black", "--treat-comment-as-code", "# %%", "--float-to-top"] - repo: local # We do not use pre-commit/mirrors-mypy, # as it comes with opinionated defaults diff --git a/docs/tutorials/harmonic_oscillator.py b/docs/tutorials/harmonic_oscillator.py index 1cf2323..6717a86 100644 --- a/docs/tutorials/harmonic_oscillator.py +++ b/docs/tutorials/harmonic_oscillator.py @@ -91,11 +91,13 @@ dfs_dho = [] for s_name, s in dho_systems.items(): - dfs_dho.append( DampedHarmonicOscillator(system=s)( - n_periods=n_periods, n_samples_per_period=n_samples_per_period - ).assign(system=rf"{s_name} (omega = {s.get('omega')}, zeta = {s.get('zeta')})") + n_periods=n_periods, + n_samples_per_period=n_samples_per_period, + ).assign( + system=rf"{s_name} (omega = {s.get('omega')}, zeta = {s.get('zeta')})", + ), ) fig = px.line( @@ -103,7 +105,7 @@ x="t", y="x", color="system", - title=rf"Damped Harmonic Oscillator", + title=r"Damped Harmonic Oscillator", labels={ "x": r"Displacement $x(t)$", "t": r"$t$", diff --git a/docs/tutorials/kepler_problem.py b/docs/tutorials/kepler_problem.py index 4fa6a21..2224ab2 100644 --- a/docs/tutorials/kepler_problem.py +++ b/docs/tutorials/kepler_problem.py @@ -22,11 +22,7 @@ # ## Usage # %% -import numpy as np -import pandas as pd -import plotly.express as px -from hamilflow.models.kepler_problem.model import Kepler2D # %% # system = {"alpha": 1.0, "mass": 1.0} diff --git a/docs/tutorials/pendulum.py b/docs/tutorials/pendulum.py index 77e0a07..ab5219c 100644 --- a/docs/tutorials/pendulum.py +++ b/docs/tutorials/pendulum.py @@ -47,7 +47,8 @@ # %% df_pen = pen.generate_from( - n_periods=n_periods, n_samples_per_period=n_samples_per_period + n_periods=n_periods, + n_samples_per_period=n_samples_per_period, ) df_pen.head() @@ -62,7 +63,7 @@ df_pen, x="t", y="x", - title=r"Simple Harmonic Oscillator ($\omega_0 = {:.4f})$".format(omega0), + title=rf"Simple Harmonic Oscillator ($\omega_0 = {omega0:.4f})$", labels=dict(x=r"Angle $\theta(t)$", t=r"Time $t$"), ) diff --git a/hamilflow/maths/trigonometrics.py b/hamilflow/maths/trigonometrics.py index 220243e..7e7a328 100644 --- a/hamilflow/maths/trigonometrics.py +++ b/hamilflow/maths/trigonometrics.py @@ -1,4 +1,3 @@ -from functools import partial from typing import TYPE_CHECKING import numpy as np diff --git a/hamilflow/models/brownian_motion.py b/hamilflow/models/brownian_motion.py index 8f455ca..e1bff11 100644 --- a/hamilflow/models/brownian_motion.py +++ b/hamilflow/models/brownian_motion.py @@ -181,7 +181,7 @@ def _trajectory(self, n_new_steps: int, seed: int) -> "npt.NDArray[np.float64]": ) step_history = np.concatenate( - (np.expand_dims(self.initial_condition.x0, axis=0), step_history) + (np.expand_dims(self.initial_condition.x0, axis=0), step_history), ) trajectory = np.cumsum(step_history, axis=0) diff --git a/hamilflow/models/free_particle.py b/hamilflow/models/free_particle.py index a1799fe..c36bfb5 100644 --- a/hamilflow/models/free_particle.py +++ b/hamilflow/models/free_particle.py @@ -39,7 +39,8 @@ class FreeParticle: """ def __init__( - self, initial_condition: Mapping[str, float | Sequence[float]] + self, + initial_condition: Mapping[str, float | Sequence[float]], ) -> None: self.initial_condition = FreeParticleIC.model_validate(initial_condition) diff --git a/hamilflow/models/harmonic_oscillator.py b/hamilflow/models/harmonic_oscillator.py index ec50690..2199e82 100644 --- a/hamilflow/models/harmonic_oscillator.py +++ b/hamilflow/models/harmonic_oscillator.py @@ -159,7 +159,7 @@ def __init__( super().__init__(system, initial_condition) if self.system.type != "simple": raise ValueError( - f"System is not a Simple Harmonic Oscillator: {self.system}" + f"System is not a Simple Harmonic Oscillator: {self.system}", ) def _x(self, t: "Sequence[float] | npt.ArrayLike") -> np.ndarray: @@ -170,7 +170,7 @@ def _x(self, t: "Sequence[float] | npt.ArrayLike") -> np.ndarray: $$ """ return self.initial_condition.x0 * np.cos( - self.system.omega * np.array(t, copy=False) + self.initial_condition.phi + self.system.omega * np.array(t, copy=False) + self.initial_condition.phi, ) @@ -232,7 +232,7 @@ def __init__( if self.system.type == "simple": raise ValueError( f"System is not a Damped Harmonic Oscillator: {self.system}\n" - f"This is a simple harmonic oscillator, use `SimpleHarmonicOscillator`." + f"This is a simple harmonic oscillator, use `SimpleHarmonicOscillator`.", ) def _x_under_damped(self, t: "Sequence[float] | npt.ArrayLike") -> npt.ArrayLike: @@ -277,7 +277,7 @@ def _x_critical_damped(self, t: "Sequence[float] | npt.ArrayLike") -> npt.ArrayL """ t = np.array(t, copy=False) return self.initial_condition.x0 * np.exp( - -self.system.zeta * self.system.omega * t + -self.system.zeta * self.system.omega * t, ) def _x_over_damped(self, t: "Sequence[float] | npt.ArrayLike") -> npt.ArrayLike: @@ -318,7 +318,7 @@ def _x(self, t: "Sequence[float] | npt.ArrayLike") -> npt.ArrayLike: x = self._x_critical_damped(t) else: raise ValueError( - "System type is not damped harmonic oscillator: {self.system.type}" + f"System type is not damped harmonic oscillator: {self.system.type}", ) return x @@ -349,11 +349,11 @@ def __init__( ) -> None: self.system = HarmonicOscillatorSystem.model_validate(system) self.initial_condition = ComplexSimpleHarmonicOscillatorIC.model_validate( - initial_condition + initial_condition, ) if self.system.type != "simple": raise ValueError( - f"System is not a Simple Harmonic Oscillator: {self.system}" + f"System is not a Simple Harmonic Oscillator: {self.system}", ) @cached_property diff --git a/hamilflow/models/harmonic_oscillator_chain.py b/hamilflow/models/harmonic_oscillator_chain.py index 98dee48..e0bbc19 100644 --- a/hamilflow/models/harmonic_oscillator_chain.py +++ b/hamilflow/models/harmonic_oscillator_chain.py @@ -92,23 +92,27 @@ def definition( ) def _z( - self, t: "Sequence[float] | npt.ArrayLike" + self, + t: "Sequence[float] | npt.ArrayLike", ) -> "tuple[npt.NDArray[np.complex64], npt.NDArray[np.complex64]]": t = np.array(t, copy=False).reshape(-1) all_travelling_waves = [self.free_mode._x(t).reshape(1, -1)] if self.independent_csho_modes: independent_cshos = np.array( - [o._z(t) for o in self.independent_csho_modes], copy=False + [o._z(t) for o in self.independent_csho_modes], + copy=False, ) all_travelling_waves.extend( - (independent_cshos, independent_cshos[::-1].conj()) - if self.odd_dof - else ( - independent_cshos[:-1], - independent_cshos[[-1]], - independent_cshos[-2::-1].conj(), - ) + ( + (independent_cshos, independent_cshos[::-1].conj()) + if self.odd_dof + else ( + independent_cshos[:-1], + independent_cshos[[-1]], + independent_cshos[-2::-1].conj(), + ) + ), ) travelling_waves = np.concatenate(all_travelling_waves) @@ -116,7 +120,8 @@ def _z( return original_zs, travelling_waves def _x( - self, t: "Sequence[float] | npt.ArrayLike" + self, + t: "Sequence[float] | npt.ArrayLike", ) -> "tuple[npt.NDArray[np.float64], npt.NDArray[np.complex64]]": original_xs, travelling_waves = self._z(t) @@ -133,7 +138,8 @@ def __call__(self, t: "Sequence[float] | npt.ArrayLike") -> pd.DataFrame: original_xs, travelling_waves = self._x(t) data = { # type: ignore [var-annotated] f"{name}{i}": cast( - "npt.NDArray[np.float64] | npt.NDArray[np.complex64]", values + "npt.NDArray[np.float64] | npt.NDArray[np.complex64]", + values, ) for name, xs in zip(("x", "y"), (original_xs, travelling_waves)) for i, values in enumerate(xs) # type: ignore [arg-type] diff --git a/hamilflow/models/kepler_problem/dynamics.py b/hamilflow/models/kepler_problem/dynamics.py index 8e609c6..165bc84 100644 --- a/hamilflow/models/kepler_problem/dynamics.py +++ b/hamilflow/models/kepler_problem/dynamics.py @@ -11,7 +11,8 @@ def _tau_of_u_exact_elliptic( - ecc: float, u: "npt.NDArray[np.float64]" + ecc: float, + u: "npt.NDArray[np.float64]", ) -> "npt.NDArray[np.float64]": cosqr, eusqrt = 1 - ecc**2, np.sqrt(ecc**2 - u**2) trig_numer = np.pi / 2 - np.arctan((ecc**2 + u) / np.sqrt(cosqr) / eusqrt) @@ -19,7 +20,8 @@ def _tau_of_u_exact_elliptic( def _tau_of_e_plus_u_elliptic( - ecc: float, u: "npt.NDArray[np.float64]" + ecc: float, + u: "npt.NDArray[np.float64]", ) -> "npt.NDArray[np.float64]": epu = np.sqrt(2 * (ecc + u) / ecc) const = np.pi / (1 - ecc**2) ** 1.5 @@ -27,7 +29,8 @@ def _tau_of_e_plus_u_elliptic( def _tau_of_e_minus_u_elliptic( - ecc: float, u: "npt.NDArray[np.float64]" + ecc: float, + u: "npt.NDArray[np.float64]", ) -> "npt.NDArray[np.float64]": emu = np.sqrt(2 * (ecc - u) / ecc) return emu / (1 + ecc) ** 2 - emu**3 * (1 + 9 * ecc) / 24 / (1 + ecc) ** 3 @@ -49,7 +52,8 @@ def tau_of_u_parabolic(ecc: float, u: "npt.ArrayLike") -> "npt.NDArray[np.float6 def _tau_of_u_exact_hyperbolic( - ecc: float, u: "npt.ArrayLike" + ecc: float, + u: "npt.ArrayLike", ) -> "npt.NDArray[np.float64]": u = np.array(u, copy=False) cosqr, eusqrt = ecc**2 - 1, np.sqrt(ecc**2 - u**2) @@ -58,7 +62,8 @@ def _tau_of_u_exact_hyperbolic( def _tau_of_1_plus_u_hyperbolic( - ecc: float, u: "npt.NDArray[np.float64]" + ecc: float, + u: "npt.NDArray[np.float64]", ) -> "npt.NDArray[np.float64]": cosqr = ecc**2 - 1 up1 = ecc * (1 + u) / 2 / cosqr @@ -68,7 +73,8 @@ def _tau_of_1_plus_u_hyperbolic( def _tau_of_e_minus_u_hyperbolic( - ecc: float, u: "npt.NDArray[np.float64]" + ecc: float, + u: "npt.NDArray[np.float64]", ) -> "npt.NDArray[np.float64]": emu = np.sqrt(2 * (ecc - u) / ecc) return emu / (1 + ecc) ** 2 + emu**3 * (1 + 9 * ecc) / 24 / (1 + ecc) ** 3 @@ -96,7 +102,8 @@ def tau_of_u_prime2(ecc: float, u: "npt.ArrayLike") -> "npt.NDArray[np.float64]" def esolve_u_from_tau_parabolic( - ecc: float, tau: "npt.ArrayLike" + ecc: float, + tau: "npt.ArrayLike", ) -> "npt.NDArray[np.float64]": tau = np.array(tau, copy=False) tau_3 = 3 * tau diff --git a/hamilflow/models/kepler_problem/model.py b/hamilflow/models/kepler_problem/model.py index 86426da..ae1aadf 100644 --- a/hamilflow/models/kepler_problem/model.py +++ b/hamilflow/models/kepler_problem/model.py @@ -100,7 +100,9 @@ def __init__( @classmethod def from_geometry( - cls, system: "Mapping[str, float]", geometries: "Mapping[str, bool | float]" + cls, + system: "Mapping[str, float]", + geometries: "Mapping[str, bool | float]", ) -> "Self": mass, alpha = system["mass"], system["alpha"] positive_angular_mom = bool(geometries["positive_angular_mom"]) @@ -162,14 +164,14 @@ def parameter(self) -> float: @cached_property def ecc(self) -> float: return math.sqrt( - 1 + 2 * self.ene * self.angular_mom**2 / self.mass / self.alpha**2 + 1 + 2 * self.ene * self.angular_mom**2 / self.mass / self.alpha**2, ) @cached_property def period_in_tau(self) -> float: if self.ecc >= 1: raise TypeError( - f"Only systems with 0 <= eccentricity < 1 have a period, got {self.ecc}" + f"Only systems with 0 <= eccentricity < 1 have a period, got {self.ecc}", ) return 2 * math.pi / (1 - self.ecc**2) ** 1.5 diff --git a/hamilflow/models/kepler_problem/numerics.py b/hamilflow/models/kepler_problem/numerics.py index 06cb981..015572f 100644 --- a/hamilflow/models/kepler_problem/numerics.py +++ b/hamilflow/models/kepler_problem/numerics.py @@ -16,7 +16,8 @@ def _u0_elliptic( - ecc: float, tau: "npt.NDArray[np.float64]" + ecc: float, + tau: "npt.NDArray[np.float64]", ) -> "npt.NDArray[np.float64]": cosqr = 1 - ecc**2 cot = 1 / np.tan(cosqr**1.5 * tau) @@ -24,7 +25,8 @@ def _u0_elliptic( def _u0_hyperbolic( - ecc: float, tau: "npt.NDArray[np.float64]" + ecc: float, + tau: "npt.NDArray[np.float64]", ) -> "npt.NDArray[np.float64]": cosqr, tau2 = ecc**2 - 1, tau**2 numer = -(cosqr**2) * tau2 + np.sqrt(ecc**2 + cosqr**3 * tau2) @@ -72,7 +74,9 @@ def f(u: float, tau: float) -> np.float64: def u_of_tau( - ecc: float, tau: "npt.ArrayLike", method: Literal["bisect", "newton"] = "bisect" + ecc: float, + tau: "npt.ArrayLike", + method: Literal["bisect", "newton"] = "bisect", ) -> "npt.NDArray[np.float64]": tau = np.array(tau, copy=False) if ecc == 0: diff --git a/hamilflow/models/pendulum.py b/hamilflow/models/pendulum.py index f29d7c5..22a6864 100644 --- a/hamilflow/models/pendulum.py +++ b/hamilflow/models/pendulum.py @@ -106,7 +106,8 @@ def period(self) -> float: return 4 * ellipk(self._math_m) / self.omega0 def _math_u( - self, t: "Sequence[float] | npt.ArrayLike" + self, + t: "Sequence[float] | npt.ArrayLike", ) -> "npt.NDArray[np.float64]": return self.omega0 * np.array(t, copy=False) diff --git a/poetry.lock b/poetry.lock index 0edb473..5c60ea5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -269,6 +269,17 @@ files = [ [package.dependencies] pycparser = "*" +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + [[package]] name = "charset-normalizer" version = "3.3.2" @@ -564,6 +575,17 @@ files = [ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, ] +[[package]] +name = "distlib" +version = "0.3.8" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -620,6 +642,22 @@ files = [ [package.extras] devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] +[[package]] +name = "filelock" +version = "3.15.4" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, + {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] +typing = ["typing-extensions (>=4.8)"] + [[package]] name = "ghp-import" version = "2.1.0" @@ -652,6 +690,20 @@ files = [ backports-strenum = {version = ">=1.3", markers = "python_version < \"3.11\""} colorama = ">=0.4" +[[package]] +name = "identify" +version = "2.6.0" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, + {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, +] + +[package.extras] +license = ["ukkonen"] + [[package]] name = "idna" version = "3.7" @@ -1372,6 +1424,17 @@ files = [ {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, ] +[[package]] +name = "nodeenv" +version = "1.9.1" +description = "Node.js virtual environment builder" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + [[package]] name = "numba" version = "0.60.0" @@ -1521,6 +1584,7 @@ optional = false python-versions = ">=3.9" files = [ {file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"}, + {file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"}, {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"}, {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"}, {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"}, @@ -1541,6 +1605,7 @@ files = [ {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"}, {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"}, {file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"}, + {file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"}, {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"}, {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"}, {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"}, @@ -1686,6 +1751,24 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pre-commit" +version = "3.8.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + [[package]] name = "prompt-toolkit" version = "3.0.36" @@ -2671,6 +2754,26 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "virtualenv" +version = "20.26.3" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, + {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + [[package]] name = "watchdog" version = "4.0.1" @@ -2778,4 +2881,4 @@ viz = ["matplotlib", "nc-time-axis", "seaborn"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "e707241ce356b9d142c7b1688f1022b93e21382d3b8ac954ae66d79306dc192a" +content-hash = "525182f8371a805376e01e6628df58a16c36255f59fa6a7980dc709669381884" diff --git a/pyproject.toml b/pyproject.toml index 87bc2d1..3bb7f88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,7 @@ plotly = "^5.23.0" [tool.poetry.group.dev.dependencies] commitizen = "*" +pre-commit = "*" [tool.commitizen] @@ -65,6 +66,23 @@ build-backend = "poetry.core.masonry.api" formats = "ipynb,py:percent" +[tool.ruff] +line-length = 88 # black default + + +[tool.ruff.lint] +select = ["ALL"] +ignore = ["D", "FA", "PLR", "S", "PD", "SLF", "PT", "FBT", "C", "ANN", "EM", "TRY", "ARG", "FIX", "TD", "TID", "ERA", "INP", "E", "SIM", "RUF", "RET"] + + +[tool.ruff.lint.isort] +known-first-party = ["hamilflow"] + + +[tool.black] +line-length = 88 # black default + + [tool.mypy] plugins = ["numpy.typing.mypy_plugin"] diff --git a/tests/models/kepler_problem/conftest.py b/tests/models/kepler_problem/conftest.py index 00c8e31..3071726 100644 --- a/tests/models/kepler_problem/conftest.py +++ b/tests/models/kepler_problem/conftest.py @@ -19,7 +19,8 @@ @pytest.fixture( - scope="module", params=[0.0, 0.1, 0.3, 0.7, 0.9, 1.0, 1.1, 2.0, 11.0, 101.0] + scope="module", + params=[0.0, 0.1, 0.3, 0.7, 0.9, 1.0, 1.1, 2.0, 11.0, 101.0], ) def ecc(request: pytest.FixtureRequest) -> float: return request.param @@ -37,7 +38,7 @@ def u_s(request: pytest.FixtureRequest, ecc: float) -> "npt.ArrayLike": @pytest.fixture(scope="module") def tau_of_u(ecc: float) -> "Callable[[float, npt.ArrayLike], npt.ArrayLike]": if ecc == 0: - pytest.skip(f"Circular case") + pytest.skip("Circular case") elif 0 < ecc < 1: return tau_of_u_elliptic elif ecc == 1: diff --git a/tests/models/kepler_problem/test_dynamics.py b/tests/models/kepler_problem/test_dynamics.py index ae978d8..45d270c 100644 --- a/tests/models/kepler_problem/test_dynamics.py +++ b/tests/models/kepler_problem/test_dynamics.py @@ -30,7 +30,9 @@ @pytest.mark.usefixtures("ecc", "u_s", "tau_of_u") class TestTauOfU: def test_const( - self, ecc: float, tau_of_u: "Callable[[float, npt.ArrayLike], npt.ArrayLike]" + self, + ecc: float, + tau_of_u: "Callable[[float, npt.ArrayLike], npt.ArrayLike]", ) -> None: # There are dividends sqrt(e**2 - u**2) and (u + 1), # hence u cannot be too close to +e / -e / -1 @@ -54,7 +56,8 @@ def integrand(u: "npt.ArrayLike") -> "npt.ArrayLike": @pytest.fixture() def exact_and_approx_tau_s( - self, ecc: float + self, + ecc: float, ) -> "tuple[Callable[[float, npt.NDArray[np.float64]], npt.NDArray[np.float64]], Callable[[float, npt.NDArray[np.float64]], npt.NDArray[np.float64]], Callable[[float, npt.NDArray[np.float64]], npt.NDArray[np.float64]]]": if ecc == 1 or ecc == 0: c = "Parabolic" if ecc else "Circular" diff --git a/tests/models/kepler_problem/test_model.py b/tests/models/kepler_problem/test_model.py index c703be7..e2707ca 100644 --- a/tests/models/kepler_problem/test_model.py +++ b/tests/models/kepler_problem/test_model.py @@ -40,7 +40,9 @@ def kepler_system(system_kwargs: "Mapping[str, float]") -> Kepler2DSystem: @pytest.fixture() def geometries( - positive_angular_mom: bool, ecc: float, parameter: float + positive_angular_mom: bool, + ecc: float, + parameter: float, ) -> dict[str, bool | float]: return dict(positive_angular_mom=positive_angular_mom, ecc=ecc, parameter=parameter) @@ -56,7 +58,6 @@ def test_raise(self, alpha: int, mass: int) -> None: class Test2DIoM: - def test_raise(self) -> None: match = "Only non-zero angular momenta are supported" with pytest.raises(NotImplementedError, match=match): diff --git a/tests/models/kepler_problem/test_numerics.py b/tests/models/kepler_problem/test_numerics.py index 17f79d1..db8db27 100644 --- a/tests/models/kepler_problem/test_numerics.py +++ b/tests/models/kepler_problem/test_numerics.py @@ -20,7 +20,7 @@ class TestUOfTau: pytest.param( "newton", marks=pytest.mark.xfail( - reason="Newton method gives nan's, possibly because of inefficient initial estimate" + reason="Newton method gives nan's, possibly because of inefficient initial estimate", ), ), ], diff --git a/tests/models/test_brownian_motion.py b/tests/models/test_brownian_motion.py index 01a5054..846468e 100644 --- a/tests/models/test_brownian_motion.py +++ b/tests/models/test_brownian_motion.py @@ -14,14 +14,14 @@ [(0.1, np.array(0.1)), (1, np.array(1.0)), ([1, 2], np.array([1, 2]))], ) def test_brownian_motion_ic(x0, expected): - brownian_motion_ic = BrownianMotionIC(x0=x0) np.testing.assert_equal(brownian_motion_ic.x0, expected) @pytest.mark.parametrize( - "sigma, delta_t, gaussian_scale", [(1, 1, 1), (1, 2, 2), (2, 1, 4)] + "sigma, delta_t, gaussian_scale", + [(1, 1, 1), (1, 2, 2), (2, 1, 4)], ) def test_brownian_motion_system(sigma, delta_t, gaussian_scale): bms = BrownianMotionSystem(sigma=sigma, delta_t=delta_t) @@ -64,7 +64,6 @@ def test_brownian_motion_system_failed_spec(sigma, delta_t): ], ) def test_brownian_motion_generate_from(sigma, x0, expected): - system = { "sigma": sigma, "delta_t": 1, @@ -119,7 +118,6 @@ def test_brownian_motion_generate_from(sigma, x0, expected): ], ) def test_brownian_motion(sigma, x0, t, expected): - system = { "sigma": sigma, "delta_t": 1, diff --git a/tests/models/test_free_particle.py b/tests/models/test_free_particle.py index 571bf78..aa64afd 100644 --- a/tests/models/test_free_particle.py +++ b/tests/models/test_free_particle.py @@ -10,15 +10,21 @@ class TestFreeParticleIC: @pytest.mark.parametrize(("x0", "v0"), [(1, 2), ((1,), (2,)), ((1, 2), (2, 3))]) def test_constructor( - self, x0: int | Sequence[int], v0: int | Sequence[int] + self, + x0: int | Sequence[int], + v0: int | Sequence[int], ) -> None: assert FreeParticleIC(x0=x0, v0=v0) @pytest.mark.parametrize( - ("x0", "v0", "expected"), [(1, (2,), TypeError), ((1,), (2, 3), ValueError)] + ("x0", "v0", "expected"), + [(1, (2,), TypeError), ((1,), (2, 3), ValueError)], ) def test_raise( - self, x0: int | Sequence[int], v0: Sequence[int], expected: type[Exception] + self, + x0: int | Sequence[int], + v0: Sequence[int], + expected: type[Exception], ) -> None: with pytest.raises(expected): FreeParticleIC(x0=x0, v0=v0) diff --git a/tests/models/test_harmonic_oscillator.py b/tests/models/test_harmonic_oscillator.py index d8a84fc..9ba262c 100644 --- a/tests/models/test_harmonic_oscillator.py +++ b/tests/models/test_harmonic_oscillator.py @@ -46,7 +46,7 @@ def test_simple_harmonic_oscillator_instantiation(zeta): {"t": 10.053096491487338, "x": 0.30901699437494723}, {"t": 11.309733552923255, "x": 0.8090169943749473}, ], - ) + ), ], ) def test_simple_harmonic_oscillator(omega, expected): @@ -153,14 +153,16 @@ def test_ic(self, kwargs: Mapping[str, tuple[int, int]]) -> None: class TestComplexHarmonicOscillator: def test_complex(self) -> None: assert ComplexSimpleHarmonicOscillator( - dict(omega=3), dict(x0=(1, 2), phi=(2, 3)) + dict(omega=3), + dict(x0=(1, 2), phi=(2, 3)), ) @pytest.mark.parametrize("zeta", [0.5, 1.0, 1.5]) def test_raise(self, zeta: float) -> None: with pytest.raises(ValueError): ComplexSimpleHarmonicOscillator( - dict(omega=3, zeta=zeta), dict(x0=(2, 3), phi=(3, 4)) + dict(omega=3, zeta=zeta), + dict(x0=(2, 3), phi=(3, 4)), ) @pytest.fixture(params=(1, (1,), [1, 2], np.array([2, 3, 5, 7, 11]))) @@ -171,10 +173,15 @@ def times(self, request: pytest.FixtureRequest) -> int | Sequence[int]: @pytest.mark.parametrize("x0", [2, 4]) @pytest.mark.parametrize("phi", [1, 6]) def test_degenerate_real( - self, omega: int, x0: int, phi: int, times: int | Sequence[int] + self, + omega: int, + x0: int, + phi: int, + times: int | Sequence[int], ) -> None: csho = ComplexSimpleHarmonicOscillator( - dict(omega=omega), dict(x0=(x0, x0), phi=(phi, phi)) + dict(omega=omega), + dict(x0=(x0, x0), phi=(phi, phi)), ) sho = SimpleHarmonicOscillator(dict(omega=omega), dict(x0=2 * x0, phi=phi)) z = np.array(csho._z(times), copy=False) diff --git a/tests/models/test_harmonic_oscillator_chain.py b/tests/models/test_harmonic_oscillator_chain.py index 5494e5a..2a6b7f6 100644 --- a/tests/models/test_harmonic_oscillator_chain.py +++ b/tests/models/test_harmonic_oscillator_chain.py @@ -1,5 +1,5 @@ from itertools import chain, product -from typing import Iterable, Mapping, Sequence, cast +from typing import Iterable, Mapping, Sequence import numpy as np import pytest @@ -28,10 +28,11 @@ def free_mode(self, request: pytest.FixtureRequest) -> dict[str, int]: @pytest.fixture( params=chain.from_iterable( product(_possible_wave_modes, repeat=r) for r in range(3) - ) + ), ) def wave_modes( - self, request: pytest.FixtureRequest + self, + request: pytest.FixtureRequest, ) -> list[dict[str, tuple[int, int]]]: return request.param @@ -41,7 +42,9 @@ def odd_dof(self, request: pytest.FixtureRequest) -> bool: @pytest.fixture() def legal_wave_modes_and_odd_def( - self, wave_modes: Iterable[Mapping[str, tuple[int, int]]], odd_dof: bool + self, + wave_modes: Iterable[Mapping[str, tuple[int, int]]], + odd_dof: bool, ) -> tuple[Iterable[Mapping[str, tuple[int, int]]], bool]: return wave_modes if odd_dof else chain(wave_modes, [dict(amp=(1, 1))]), odd_dof @@ -54,7 +57,8 @@ def test_init( omega: int, free_mode: Mapping[str, int], legal_wave_modes_and_odd_def: tuple[ - Iterable[Mapping[str, tuple[int, int]]], bool + Iterable[Mapping[str, tuple[int, int]]], + bool, ], ) -> None: wave_modes, odd_dof = legal_wave_modes_and_odd_def @@ -66,7 +70,8 @@ def hoc_and_zs( omega: int, free_mode: Mapping[str, int], legal_wave_modes_and_odd_def: tuple[ - Iterable[Mapping[str, tuple[int, int]]], bool + Iterable[Mapping[str, tuple[int, int]]], + bool, ], times: int | Sequence[int], ) -> tuple[HarmonicOscillatorsChain, np.ndarray, np.ndarray]: @@ -75,20 +80,25 @@ def hoc_and_zs( return (hoc, *hoc._z(times)) def test_real( - self, hoc_and_zs: tuple[HarmonicOscillatorsChain, np.ndarray, np.ndarray] + self, + hoc_and_zs: tuple[HarmonicOscillatorsChain, np.ndarray, np.ndarray], ) -> None: _, original_zs, _ = hoc_and_zs assert np.all(original_zs.imag == 0.0) def test_dof( - self, hoc_and_zs: tuple[HarmonicOscillatorsChain, np.ndarray, np.ndarray] + self, + hoc_and_zs: tuple[HarmonicOscillatorsChain, np.ndarray, np.ndarray], ) -> None: hoc, original_zs, _ = hoc_and_zs assert original_zs.shape[0] == hoc.n_dof @pytest.mark.parametrize("wave_mode", [None, *_possible_wave_modes[1:]]) def test_raise( - self, omega: int, free_mode: Mapping[str, int], wave_mode: Mapping[str, int] + self, + omega: int, + free_mode: Mapping[str, int], + wave_mode: Mapping[str, int], ) -> None: ics = [free_mode, *([wave_mode] if wave_mode else [])] with pytest.raises(ValueError): diff --git a/tests/models/test_pendulum.py b/tests/models/test_pendulum.py index 8ba8d58..6fb643c 100644 --- a/tests/models/test_pendulum.py +++ b/tests/models/test_pendulum.py @@ -52,7 +52,10 @@ def test_period_static(self, omega0: float, theta0: float, period: float) -> Non assert pytest.approx(p.period) == period def test_transf( - self, omega0: float, theta0: float, times: "Sequence[float] | npt.ArrayLike" + self, + omega0: float, + theta0: float, + times: "Sequence[float] | npt.ArrayLike", ) -> None: p = Pendulum(omega0, theta0) arr_times = np.asarray(times) @@ -62,7 +65,10 @@ def test_transf( assert_array_almost_equal(theta_terms, sin_u) def test_period_dynamic_theta( - self, omega0: float, theta0: float, times: "Sequence[float] | npt.ArrayLike" + self, + omega0: float, + theta0: float, + times: "Sequence[float] | npt.ArrayLike", ) -> None: p = Pendulum(omega0, theta0) arr_times_1 = np.array(times, copy=False) + p.period