diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fd69cb9..ab3381c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,9 +18,9 @@ jobs: package: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: '3.10' - name: Install dependencies @@ -34,7 +34,7 @@ jobs: - name: Check env vars run: | echo "Triggered by: ${{ github.event_name }}" - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v7 with: name: dist path: dist @@ -48,7 +48,7 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@v6 + - uses: actions/download-artifact@v8 with: name: dist path: dist diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 77f0d1b..4570f90 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -38,10 +38,10 @@ jobs: OPENBLAS_NUM_THREADS: "1" PYTHONUNBUFFERED: "1" steps: - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: pyvista/setup-headless-display-action@main with: qt: true @@ -64,26 +64,33 @@ jobs: run: python -m coverage run && coverage report test_conda: - timeout-minutes: 90 + timeout-minutes: 60 runs-on: ubuntu-latest defaults: run: shell: bash -el {0} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + python-version: "3.14" + - os: macos-15-intel + python-version: "3.14" env: MKL_NUM_THREADS: '1' PYTHONUNBUFFERED: '1' - PYTHON_VERSION: '3.13' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: pyvista/setup-headless-display-action@main with: qt: true pyvista: false - - uses: mamba-org/setup-micromamba@v2 + - uses: mamba-org/setup-micromamba@v3 with: environment-file: environment.yml create-args: >- # beware the >- instead of |, we don't split on newlines but on spaces - python=${{ env.PYTHON_VERSION }} + python=${{ matrix.python-version }} - name: Install package and test dependencies run: | pip install -e . @@ -108,10 +115,10 @@ jobs: OPENBLAS_NUM_THREADS: "1" PYTHONUNBUFFERED: "1" steps: - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v7 with: python-version: "3.10" - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: pyvista/setup-headless-display-action@main with: qt: true @@ -119,17 +126,14 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip setuptools wheel - pip install --upgrade --upgrade-strategy eager .[test] + pip install -e . --no-deps + pip install -r tools/requirements_old.txt - name: Display versions and environment information run: | echo $TZ date - python --version which python - - run: | - pip install -e . --no-deps - pip install -r tools/requirements_old.txt - - run: python -c "import pybispectra; import mne; print(f'PyBispectra {pybispectra.__version__}\n'); mne.sys_info()" + python -c "import pybispectra; import mne; print(f'PyBispectra {pybispectra.__version__}\n'); mne.sys_info()" - name: Download testing data run: python -c "from pybispectra.utils import DATASETS, get_example_data_paths; (get_example_data_paths(data) for data in DATASETS.keys())" - name: Run pytest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c9a21d0..1c5f94e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: # ruff PyBispectra - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.8 + rev: v0.16.0 hooks: - id: ruff name: ruff lint pybispectra @@ -10,7 +10,7 @@ repos: # ruff examples - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.8 + rev: v0.16.0 hooks: - id: ruff name: ruff lint examples @@ -19,7 +19,7 @@ repos: # codespell - repo: https://github.com/codespell-project/codespell - rev: v2.4.1 + rev: v2.4.3 hooks: - id: codespell additional_dependencies: @@ -29,7 +29,7 @@ repos: # yamllint - repo: https://github.com/adrienverge/yamllint.git - rev: v1.37.1 + rev: v1.38.0 hooks: - id: yamllint args: [--strict, -c, .yamllint.yml] @@ -45,7 +45,7 @@ repos: # toml-sort - repo: https://github.com/pappasam/toml-sort.git - rev: v0.24.3 + rev: v0.24.4 hooks: - id: toml-sort-fix diff --git a/LICENSE.txt b/LICENSE.txt index a7d06ae..364d808 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023-2025 Thomas Samuel Binns +Copyright (c) 2023-2026 Thomas Samuel Binns Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/changelog.md b/changelog.md index 2f4ac73..0311962 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,20 @@ No changes. ## [Version 1.3](https://pybispectra.readthedocs.io/1.3/) +### Version 1.3.2 + +##### Dependencies +- Dropped max supported Python version being pinned. + +
+ +### Version 1.3.1 + +##### Dependencies +- Added support for Python 3.14 in the `conda` environment. + +
+ ### Version 1.3.0 ##### Enhancements diff --git a/docs/Makefile b/docs/Makefile index d0c3cbf..06e1859 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -18,3 +18,11 @@ help: # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +clean: + rm -rf $(BUILDDIR)/* + rm -rf $(SOURCEDIR)/auto_examples/* + rm -rf $(SOURCEDIR)/generated/* + +view: + @python -c "import webbrowser; webbrowser.open_new_tab('file://$(PWD)/build/html/index.html')" diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css index ca373b3..d4d7a90 100644 --- a/docs/source/_static/css/custom.css +++ b/docs/source/_static/css/custom.css @@ -4,4 +4,49 @@ div { ul { text-align: left +} + +/* widen main content area */ +.bd-page-width { + max-width: 100rem; +} + +/* make versionadded smaller and inline with param name */ +/* don't do for deprecated / versionchanged; they have extra info (too long to fit) */ +div.versionadded>p { + margin-top: 0; + margin-bottom: 0; +} + +div.versionadded { + margin: 0; + margin-left: 0.5rem; + display: inline-block; +} + +/* when FF supports :has(), change to → dd > p:has(+div.versionadded) */ +dd>p { + display: inline; +} + +@media (max-width: 1199.98px) { + .bd-header .navbar-header-items__start { + flex-shrink: 1; + min-width: 0; + max-width: 45%; + } + + .bd-header .navbar-header-items__start .navbar-item, + .bd-header .navbar-brand { + min-width: 0; + max-width: 100%; + flex-shrink: 1; + } + + .bd-header .navbar-brand .logo__title { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } \ No newline at end of file diff --git a/docs/source/_static/versions.json b/docs/source/_static/versions.json index 2796258..ec275f0 100644 --- a/docs/source/_static/versions.json +++ b/docs/source/_static/versions.json @@ -1,12 +1,12 @@ [ { "name": "dev", - "version": "1.3.1+dev", + "version": "1.4.0+dev", "url": "https://pybispectra.readthedocs.io/latest/" }, { "name": "1.3 (stable)", - "version": "1.3.0", + "version": "1.3.2", "url": "https://pybispectra.readthedocs.io/1.3/" }, { diff --git a/docs/source/conf.py b/docs/source/conf.py index 6d28dc0..5a1ac63 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -14,9 +14,9 @@ from pybispectra.utils._docs import linkcode_resolve project = "PyBispectra" -copyright = "2023-2025, Thomas S. Binns" +copyright = "2023-2026, Thomas S. Binns" author = "Thomas S. Binns" -release = "1.3.0" +release = "1.3.2" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration @@ -36,6 +36,7 @@ "sphinxcontrib.bibtex", "sphinx_gallery.gen_gallery", "sphinx_copybutton", + "sphinx_design", ### Custom "directive_formatting", ] diff --git a/docs/source/installation.rst b/docs/source/installation.rst index 25998fa..04ee5e6 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -1,40 +1,74 @@ Installation ============ -To install PyBispectra, activate the desired environment in which you want the package, -then install it using `pip `_: +PyBispectra is available on `PyPI `_, and +`conda-forge `_ +for version ≥ 1.2.2. + +PyBispectra requires Python ≥ 3.10. + + +Package installation +-------------------- + +To install PyBispectra, activate the desired environment or project in which you want +the package, then install it using `pip `_: .. code-block:: pip install pybispectra -or `conda `_ from -`conda-forge `_ (for PyBispectra ≥ 1.2.2): +`uv `_: + +.. code-block:: + + uv pip install pybispectra + +`conda `_: .. code-block:: conda install -c conda-forge pybispectra -PyBispectra requires Python ≥ 3.10. +or `pixi `_: -If you need to create an environment in which to install PyBispectra, you can do so -using `conda `_, -`venv `_, or -`uv `_. +.. code-block:: + + pixi add pybispectra -With ``conda`` --------------- +| -In a shell with ``conda`` available, run the following commands: +.. dropdown:: Compatibility for newly released Python versions + :icon: alert + :color: info -.. code-block:: + If you encounter issues installing PyBispectra in environments with newly released Python versions, this may be due to a lack of compatible ``numba`` releases, one of PyBispectra's core dependencies. + + ``numba`` is not always immediately compatible with new Python versions, and there may be a delay of several weeks before a compatible version is released. - conda create -n pybispectra_env - conda activate pybispectra_env - conda install -c conda-forge pybispectra + You can find the supported Python versions for ``numba`` in this `table `_. + + If a compatible ``numba`` release is available for your environment's Python version and you are still encountering installation issues, please report this on the `PyBispectra issue page `_. + +.. dropdown:: Compatibility with Python ≥ 3.14 on macOS Intel systems + :icon: alert + :color: info + + Due to wheel availability limitations for ``llvmlite`` on macOS Intel systems with Python ≥ 3.14, installation issues can arise when using ``pip`` and ``uv``. + + If you have a macOS Intel system and need to use Python ≥ 3.14, consider using ``conda`` or ``pixi`` for an easier installation. + + +Creating an environment or project for installation +--------------------------------------------------- + +If you need to create an environment or project in which to install PyBispectra, you can +do so using `venv `_, +`uv `_, `pixi `_, or +`conda `_. With ``venv`` -------------- +~~~~~~~~~~~~~ In a shell with Python available, navigate to your project location and create the environment: @@ -52,7 +86,7 @@ then install the package: pip install pybispectra With ``uv`` ------------ +~~~~~~~~~~~ In a shell with ``uv`` available, navigate to your project location and create the environment: @@ -68,3 +102,25 @@ then install the package: .. code-block:: uv pip install pybispectra + +With ``pixi`` +~~~~~~~~~~~~~ + +In a shell with ``pixi`` available, run the following commands: + +.. code-block:: + + pixi init + pixi shell-hook + pixi add pybispectra + +With ``conda`` +~~~~~~~~~~~~~~ + +In a shell with ``conda`` available, run the following commands: + +.. code-block:: + + conda create -n pybispectra_env + conda activate pybispectra_env + conda install -c conda-forge pybispectra diff --git a/environment.yml b/environment.yml index cbb450d..631712f 100644 --- a/environment.yml +++ b/environment.yml @@ -2,10 +2,10 @@ name: pybispectra channels: - conda-forge dependencies: - - python>=3.10,<3.14 + - python>=3.10 - joblib>=1.2 - matplotlib>=3.6 - - mne>=1.7 + - mne-base>=1.7 - numba>=0.56 - numpy>=1.22 - scikit-learn>=1.1 diff --git a/examples/plot_compute_time_resolved.py b/examples/plot_compute_time_resolved.py index ba9cd46..7759b03 100644 --- a/examples/plot_compute_time_resolved.py +++ b/examples/plot_compute_time_resolved.py @@ -18,7 +18,7 @@ from matplotlib import pyplot as plt from numpy.random import RandomState -from pybispectra import WaveShape, get_example_data_paths, compute_tfr +from pybispectra import WaveShape, compute_tfr, get_example_data_paths ######################################################################################## # Background diff --git a/pyproject.toml b/pyproject.toml index 3361588..2b80b9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ dynamic = [ ] # check tools/hatch_build.py for details name = "pybispectra" readme = "README.md" -version = "1.3.0" +version = "1.3.2" [project.optional-dependencies] dev = ["pybispectra[doc]", "pybispectra[lint]", "pybispectra[test]"] @@ -30,6 +30,7 @@ doc = [ "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", + "sphinx-design", "sphinx-gallery>=0.18", "sphinxcontrib-bibtex", ] @@ -125,7 +126,11 @@ ignore_roles = [ report_level = "WARNING" [tool.ruff] -extend-exclude = ["docs", "examples/compute_*.py"] +extend-exclude = [ + "docs", + "examples/compute_*.py", + "src/pybispectra/utils/_docs.py", +] line-length = 88 [tool.ruff.lint.per-file-ignores] diff --git a/src/pybispectra/__init__.py b/src/pybispectra/__init__.py index b05bf70..1a66d0f 100644 --- a/src/pybispectra/__init__.py +++ b/src/pybispectra/__init__.py @@ -1,6 +1,6 @@ """Initialisation of the PyBispectra package.""" -__version__ = "1.3.0" +__version__ = "1.3.2" from .cfc import AAC, PAC, PPC from .general import Bispectrum, Threenorm diff --git a/src/pybispectra/cfc/aac.py b/src/pybispectra/cfc/aac.py index 9335d8c..5067b9f 100644 --- a/src/pybispectra/cfc/aac.py +++ b/src/pybispectra/cfc/aac.py @@ -7,9 +7,9 @@ from pybispectra.utils._defaults import _precision from pybispectra.utils._process import _ProcessFreqBase from pybispectra.utils._utils import ( + _compute_in_parallel, _compute_pearsonr_2d, _fast_find_first, - _compute_in_parallel, ) @@ -61,7 +61,7 @@ class AAC(_ProcessFreqBase): verbose : bool Whether or not to report the progress of the processing. - """ # noqa: E501 + """ _data_precision: type = _precision.real # Real-valued TFR power @@ -72,9 +72,9 @@ class AAC(_ProcessFreqBase): def compute( self, indices: tuple[tuple[int]] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_jobs: int = 1, ) -> None: r"""Compute AAC, averaged over epochs. diff --git a/src/pybispectra/cfc/pac.py b/src/pybispectra/cfc/pac.py index 937b69c..feaab72 100644 --- a/src/pybispectra/cfc/pac.py +++ b/src/pybispectra/cfc/pac.py @@ -80,9 +80,9 @@ class PAC(_ProcessBispectrum): def compute( self, indices: tuple[tuple[int]] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, antisym: bool | tuple[bool] = False, norm: bool | tuple[bool] = False, n_jobs: int = 1, @@ -181,7 +181,7 @@ def compute( References ---------- .. footbibliography:: - """ # noqa: E501 + """ self._reset_attrs() self._sort_metrics(antisym, norm) diff --git a/src/pybispectra/cfc/ppc.py b/src/pybispectra/cfc/ppc.py index b09f280..361eab2 100644 --- a/src/pybispectra/cfc/ppc.py +++ b/src/pybispectra/cfc/ppc.py @@ -6,7 +6,7 @@ from pybispectra.utils import ResultsCFC from pybispectra.utils._defaults import _precision from pybispectra.utils._process import _ProcessFreqBase -from pybispectra.utils._utils import _fast_find_first, _compute_in_parallel +from pybispectra.utils._utils import _compute_in_parallel, _fast_find_first class PPC(_ProcessFreqBase): @@ -73,9 +73,9 @@ class PPC(_ProcessFreqBase): def compute( self, indices: tuple[tuple[int]] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_jobs: int = 1, ) -> None: r"""Compute PPC, averaged over epochs. diff --git a/src/pybispectra/general/general.py b/src/pybispectra/general/general.py index 98d3be8..fdbacc2 100644 --- a/src/pybispectra/general/general.py +++ b/src/pybispectra/general/general.py @@ -22,16 +22,14 @@ class _General(_ProcessBispectrum): def _sort_indices(self, indices: tuple[tuple[int]] | None) -> None: """Sort kmn channel indices inputs.""" if indices is None: - indices = tuple( - [ - tuple(np.tile(range(self._n_chans), self._n_chans**2).tolist()), - tuple( - np.repeat( - np.tile(range(self._n_chans), self._n_chans), self._n_chans - ).tolist() - ), - tuple(np.repeat(range(self._n_chans), self._n_chans**2).tolist()), - ] + indices = ( + tuple(np.tile(range(self._n_chans), self._n_chans**2).tolist()), + tuple( + np.repeat( + np.tile(range(self._n_chans), self._n_chans), self._n_chans + ).tolist() + ), + tuple(np.repeat(range(self._n_chans), self._n_chans**2).tolist()), ) if not isinstance(indices, tuple): raise TypeError("`indices` must be a tuple.") @@ -118,9 +116,9 @@ class Bispectrum(_General): def compute( self, indices: tuple[tuple[int]] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_jobs: int = 1, ) -> None: r"""Compute the bispectrum, averaged over epochs. @@ -167,7 +165,7 @@ def compute( .. warning:: For values of ``f1s`` higher than ``f2s`` or where ``f2s + f1s`` exceeds the Nyquist frequency, a :obj:`numpy.nan` value is returned. - """ # noqa: E501 + """ self._reset_attrs() self._sort_indices(indices) @@ -305,9 +303,9 @@ class Threenorm(_General): def compute( self, indices: tuple[tuple[int]] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_jobs: int = 1, ) -> None: r"""Compute the threenorm, averaged over epochs. diff --git a/src/pybispectra/tde/tde.py b/src/pybispectra/tde/tde.py index 748cfff..bfffea5 100644 --- a/src/pybispectra/tde/tde.py +++ b/src/pybispectra/tde/tde.py @@ -1,7 +1,8 @@ """Tools for handling TDE analysis.""" +from collections.abc import Callable from copy import deepcopy -from typing import Callable +from typing import ClassVar import numpy as np from numba import njit @@ -10,7 +11,7 @@ from pybispectra.utils import ResultsTDE from pybispectra.utils._defaults import _precision from pybispectra.utils._process import _ProcessBispectrum -from pybispectra.utils._utils import _compute_in_parallel, _number_like, _int_like +from pybispectra.utils._utils import _compute_in_parallel, _int_like, _number_like class TDE(_ProcessBispectrum): @@ -97,7 +98,7 @@ class TDE(_ProcessBispectrum): _tde_iv_nosym: np.ndarray = None _tde_iv_antisym: np.ndarray = None - _kmn: dict = { + _kmn: ClassVar[dict] = { "xxx": (0, 0, 0), "yyy": (1, 1, 1), "xyx": (0, 1, 0), @@ -109,9 +110,9 @@ def __init__( self, data: np.ndarray, freqs: np.ndarray, - sampling_freq: int | float, + sampling_freq: float, verbose: bool = True, - ) -> None: # noqa: D107 + ) -> None: super().__init__(data, freqs, sampling_freq, times=None, verbose=verbose) self._sort_fft_coeffs() @@ -130,8 +131,8 @@ def _sort_fft_coeffs(self) -> None: def compute( self, indices: tuple[tuple[int]] | None = None, - fmin: int | float | tuple[int | float] = 0.0, - fmax: int | float | tuple[int | float] = np.inf, + fmin: float | tuple[float] = 0.0, + fmax: float | tuple[float] = np.inf, antisym: bool | tuple[bool] = False, method: int | tuple[int] = 1, n_jobs: int = 1, @@ -284,9 +285,7 @@ def _reset_attrs(self) -> None: self._xyz = None def _sort_freq_bands( - self, - fmin: int | float | tuple[int | float], - fmax: int | float | tuple[int | float], + self, fmin: float | tuple[float], fmax: float | tuple[float] ) -> None: """Sort inputs for the frequency bounds.""" if not isinstance(fmin, _number_like + (tuple,)): diff --git a/src/pybispectra/utils/_defaults.py b/src/pybispectra/utils/_defaults.py index fc35a9b..14156cf 100644 --- a/src/pybispectra/utils/_defaults.py +++ b/src/pybispectra/utils/_defaults.py @@ -9,7 +9,7 @@ class _Precision: Double precision (i.e., float64 and complex128) used by default. """ - def __init__(self) -> None: # noqa: D107 + def __init__(self) -> None: self.type = "double" self.real = np.float64 self.complex = np.complex128 diff --git a/src/pybispectra/utils/_plot.py b/src/pybispectra/utils/_plot.py index e7eb70d..c28a3e9 100644 --- a/src/pybispectra/utils/_plot.py +++ b/src/pybispectra/utils/_plot.py @@ -44,8 +44,8 @@ def _sort_plot_inputs( nodes: int | tuple[int] | None, n_rows: int, n_cols: int, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, ) -> tuple[int]: """Sort the plotting inputs. @@ -142,7 +142,7 @@ def _sort_freq_inputs( return f1s, f2s, f1_idcs, f2_idcs def _sort_time_inputs( - self, times: tuple[int | float] | None + self, times: tuple[float] | None ) -> tuple[np.ndarray | None, np.ndarray | None]: """Sort `times` input. @@ -234,7 +234,7 @@ def __init__( f2s: np.ndarray, times: np.ndarray | None, name: str, - ) -> None: # noqa: D107 + ) -> None: super().__init__(data, indices, name) self.f1s = f1s.copy() @@ -244,13 +244,13 @@ def __init__( def plot( self, nodes: int | tuple[int] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_rows: int = 1, n_cols: int = 1, - major_tick_intervals: int | float = 5.0, - minor_tick_intervals: int | float = 1.0, + major_tick_intervals: float = 5.0, + minor_tick_intervals: float = 1.0, plot_absolute: bool = False, mirror_cbar_range: bool = True, cbar_range_abs: tuple[float] | list[tuple[float]] | None = None, @@ -400,13 +400,13 @@ def plot( def _sort_plot_inputs( self, nodes: int | tuple[int] | None, - f1s: tuple[int | float] | None, - f2s: tuple[int | float] | None, - times: tuple[int | float] | None, + f1s: tuple[float] | None, + f2s: tuple[float] | None, + times: tuple[float] | None, n_rows: int, n_cols: int, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, plot_absolute: bool, mirror_cbar_range: bool, cbar_range_abs: tuple[float] | list[tuple[float]] | None, @@ -469,8 +469,9 @@ def _sort_plot_inputs( cbar_range_phase, ] cbar_names = ["abs", "real", "imag", "phase"] - cbar_idx = 0 - for cbar_range, cbar_name in zip(cbar_ranges, cbar_names): + for cbar_idx, (cbar_range, cbar_name) in enumerate( + zip(cbar_ranges, cbar_names) + ): if not isinstance(cbar_range, (list, tuple, type(None))): raise TypeError( f"`cbar_range_{cbar_name}` must be a list, tuple, or None." @@ -490,7 +491,6 @@ def _sort_plot_inputs( f"Limits in `cbar_range_{cbar_name}` must have length of 2." ) cbar_ranges[cbar_idx] = cbar_range - cbar_idx += 1 return (nodes, f1s, f2s, f1_idcs, f2_idcs, times, time_idcs, cbar_ranges) @@ -555,8 +555,8 @@ def _plot_results( time_idcs: np.ndarray | None, n_rows: int, n_cols: int, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, plot_absolute: bool, mirror_cbar_range: bool, cbar_ranges: list[list[tuple[float | None]]], @@ -711,8 +711,8 @@ def _plot_results( def _set_axis_ticks( self, axis: plt.Axes, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, ) -> None: """Set major and minor tick intervals of x- and y-axes.""" axis.xaxis.set_major_locator(plt.MultipleLocator(major_tick_intervals)) @@ -757,7 +757,7 @@ def __init__( f2s: np.ndarray, times: np.ndarray | None, name: str, - ) -> None: # noqa: D107 + ) -> None: super().__init__(data, indices, name) self.f1s = f1s.copy() @@ -767,13 +767,13 @@ def __init__( def plot( self, nodes: int | tuple[int] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_rows: int = 1, n_cols: int = 1, - major_tick_intervals: int | float = 5.0, - minor_tick_intervals: int | float = 1.0, + major_tick_intervals: float = 5.0, + minor_tick_intervals: float = 1.0, cbar_range: tuple[float] | list[tuple[float]] | None = None, show: bool = True, ) -> tuple[list[Figure], list[np.ndarray]]: @@ -836,7 +836,7 @@ def plot( ----- ``n_rows`` and ``n_cols`` of ``1`` will plot the results for each node on a new figure. - """ # noqa: E501 + """ nodes, f1s, f2s, f1_idcs, f2_idcs, times, time_idcs, cbar_range = ( self._sort_plot_inputs( nodes, @@ -876,13 +876,13 @@ def plot( def _sort_plot_inputs( self, nodes: int | tuple[int] | None, - f1s: tuple[int | float] | None, - f2s: tuple[int | float] | None, - times: tuple[int | float] | None, + f1s: tuple[float] | None, + f2s: tuple[float] | None, + times: tuple[float] | None, n_rows: int, n_cols: int, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, cbar_range: tuple[float] | list[tuple[float]] | None, ) -> tuple[ tuple[int], @@ -956,8 +956,8 @@ def _plot_results( time_idcs: np.ndarray | None, n_rows: int, n_cols: int, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, cbar_range: list[tuple[float | None]], ) -> tuple[list[Figure], list[np.ndarray]]: """Plot results on the relevant figures/subplots.""" @@ -1043,8 +1043,8 @@ def _plot_results( def _set_axis_ticks( self, axis: plt.Axes, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, ) -> None: """Set major and minor tick intervals of x- and y-axes.""" axis.xaxis.set_major_locator(plt.MultipleLocator(major_tick_intervals)) @@ -1086,7 +1086,7 @@ def __init__( freq_bands: tuple[tuple[float]] | None, times: np.ndarray, name: str, - ) -> None: # noqa: D107 + ) -> None: super().__init__(data, indices, name) self.tau = tau @@ -1102,11 +1102,11 @@ def plot( self, nodes: int | tuple[int] | None = None, freq_bands: int | tuple[int] | None = None, - times: tuple[int | float] | None = None, + times: tuple[float] | None = None, n_rows: int = 1, n_cols: int = 1, - major_tick_intervals: int | float = 500.0, - minor_tick_intervals: int | float = 100.0, + major_tick_intervals: float = 500.0, + minor_tick_intervals: float = 100.0, show: bool = True, ) -> tuple[list[Figure], list[np.ndarray]]: """Plot the results. @@ -1189,7 +1189,7 @@ def _sort_plot_inputs( self, nodes: int | tuple[int] | None, freq_bands: int | tuple[int] | None, - times: tuple[int | float] | None, + times: tuple[float] | None, n_rows: int, n_cols: int, major_tick_intervals: float, @@ -1290,8 +1290,8 @@ def _plot_results( time_idcs: np.ndarray, n_rows: int, n_cols: int, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, ) -> tuple[list[Figure], list[np.ndarray]]: """Plot results on the relevant figures/subplots.""" fig_i = 0 @@ -1385,8 +1385,8 @@ def _mark_delay( def _set_axis_ticks( self, axis: plt.Axes, - major_tick_intervals: int | float, - minor_tick_intervals: int | float, + major_tick_intervals: float, + minor_tick_intervals: float, ) -> None: """Set major and minor tick intervals of the x-axis.""" axis.xaxis.set_major_locator(plt.MultipleLocator(major_tick_intervals)) diff --git a/src/pybispectra/utils/_process.py b/src/pybispectra/utils/_process.py index ddc49f2..6a66dc5 100644 --- a/src/pybispectra/utils/_process.py +++ b/src/pybispectra/utils/_process.py @@ -39,7 +39,7 @@ def __init__( self, data: np.ndarray, freqs: np.ndarray, - sampling_freq: int | float, + sampling_freq: float, times: np.ndarray | None = None, verbose: bool = True, ) -> None: @@ -49,7 +49,7 @@ def _sort_init_inputs( self, data: np.ndarray, freqs: np.ndarray, - sampling_freq: int | float, + sampling_freq: float, times: np.ndarray | None, verbose: bool, ) -> None: @@ -135,11 +135,9 @@ def _sort_init_inputs( def _sort_indices(self, indices: tuple[tuple[int]] | None) -> None: """Sort seed-target indices inputs.""" if indices is None: - indices = tuple( - [ - tuple(np.tile(range(self._n_chans), self._n_chans).tolist()), - tuple(np.repeat(range(self._n_chans), self._n_chans).tolist()), - ] + indices = ( + tuple(np.tile(range(self._n_chans), self._n_chans).tolist()), + tuple(np.repeat(range(self._n_chans), self._n_chans).tolist()), ) if not isinstance(indices, tuple): raise TypeError("`indices` must be a tuple.") @@ -167,9 +165,7 @@ def _sort_indices(self, indices: tuple[tuple[int]] | None) -> None: self._n_cons = len(seeds) - def _sort_freqs( - self, f1s: tuple[int | float] | None, f2s: tuple[int | float] | None - ) -> None: + def _sort_freqs(self, f1s: tuple[float] | None, f2s: tuple[float] | None) -> None: """Sort frequency inputs.""" check_f1s = True check_f2s = True @@ -208,15 +204,14 @@ def _sort_freqs( ) self._f2s = self.freqs[f2_idcs] - if self.verbose: - if self._f1s.max() >= self._f2s.min(): - warn( - "At least one value in `f1s` is >= a value in `f2s`. The " - "corresponding result(s) will have a value of NaN.", - UserWarning, - ) + if self.verbose and self._f1s.max() >= self._f2s.min(): + warn( + "At least one value in `f1s` is >= a value in `f2s`. The corresponding " + "result(s) will have a value of NaN.", + UserWarning, + ) - def _sort_tmin_tmax(self, times: tuple[int | float] | None) -> None: + def _sort_tmin_tmax(self, times: tuple[float] | None) -> None: """Sort time range inputs.""" if times is None: times = (-np.inf, np.inf) @@ -308,34 +303,33 @@ def _sort_indices(self, indices: tuple[tuple[int]]) -> None: """Sort seed-target indices inputs.""" super()._sort_indices(indices) - if self.verbose: - if self._return_antisym and ( + if ( + self.verbose + and self._return_antisym + and ( any(seed == target for seed, target in zip(self._seeds, self._targets)) - ): - warn( - "The seed and target for at least one connection is the same " - "channel. The corresponding antisymmetrised result(s) will be " - "NaN-valued.", - UserWarning, - ) + ) + ): + warn( + "The seed and target for at least one connection is the same channel. " + "The corresponding antisymmetrised result(s) will be NaN-valued.", + UserWarning, + ) - def _sort_freqs( - self, f1s: tuple[int | float] | None, f2s: tuple[int | float] | None - ) -> None: + def _sort_freqs(self, f1s: tuple[float] | None, f2s: tuple[float] | None) -> None: """Sort frequency inputs.""" super()._sort_freqs(f1s, f2s) - if self.verbose: - if any( - hfreq + lfreq not in self.freqs - for hfreq in self._f2s - for lfreq in self._f1s - ): - warn( - "At least one value of `f2s` + `f1s` is not present in the " - "frequencies. The corresponding result(s) will be NaN-valued.", - UserWarning, - ) + if self.verbose and any( + hfreq + lfreq not in self.freqs + for hfreq in self._f2s + for lfreq in self._f1s + ): + warn( + "At least one value of `f2s` + `f1s` is not present in the " + "frequencies. The corresponding result(s) will be NaN-valued.", + UserWarning, + ) @njit diff --git a/src/pybispectra/utils/_utils.py b/src/pybispectra/utils/_utils.py index d455351..f1eedb3 100644 --- a/src/pybispectra/utils/_utils.py +++ b/src/pybispectra/utils/_utils.py @@ -8,7 +8,6 @@ from pybispectra.utils._defaults import _precision - # Aliases for type checking _int_like = (int, np.integer) _float_like = (float, np.floating) @@ -109,7 +108,7 @@ def _get_block_indices(block_i: int, limit: int, n_jobs: int) -> np.ndarray: @njit def _fast_find_first( - vector: np.ndarray, value: int | float, start_idx: int = 0 + vector: np.ndarray, value: float, start_idx: int = 0 ) -> int: # pragma: no cover """Quickly find the first index of a value in a 1D array using Numba. diff --git a/src/pybispectra/utils/ged.py b/src/pybispectra/utils/ged.py index b04db4c..9131313 100644 --- a/src/pybispectra/utils/ged.py +++ b/src/pybispectra/utils/ged.py @@ -1,14 +1,15 @@ """Tools for performing generalised eigendecompositions.""" -from packaging.version import Version from multiprocessing import cpu_count from warnings import warn import numpy as np import scipy as sp -from mne import Info, __version__ as mne_version +from mne import Info +from mne import __version__ as mne_version from mne.decoding import SSD from mne.time_frequency import csd_array_fourier, csd_array_multitaper +from packaging.version import Version from pybispectra.utils._defaults import _precision from pybispectra.utils._utils import _create_mne_info, _int_like, _number_like @@ -168,9 +169,9 @@ class SpatioSpectralFilter: def __init__( self, data: np.ndarray, - sampling_freq: int | float, + sampling_freq: float, verbose: bool = True, - ) -> None: # noqa: D107 + ) -> None: self.verbose = verbose self._sort_init_inputs(data, sampling_freq) @@ -193,9 +194,9 @@ def _sort_init_inputs(self, data: np.ndarray, sampling_freq: float) -> None: def _sort_freq_bounds( self, - signal_bounds: tuple[int | float], - noise_bounds: tuple[int | float], - signal_noise_gap: int | float, + signal_bounds: tuple[float], + noise_bounds: tuple[float], + signal_noise_gap: float, ) -> None: """Sort frequency bound inputs.""" if not isinstance(signal_bounds, tuple) or not all( @@ -307,9 +308,9 @@ def _sort_csd_method(self, csd_method: str) -> None: def fit_ssd( self, - signal_bounds: tuple[int | float], - noise_bounds: tuple[int | float], - signal_noise_gap: int | float = 1.0, + signal_bounds: tuple[float], + noise_bounds: tuple[float], + signal_noise_gap: float = 1.0, bandpass_filter: bool = False, indices: tuple[int] | None = None, rank: int | None = None, @@ -373,9 +374,9 @@ def fit_ssd( def _create_mne_filt_params( self, - signal_bounds: tuple[int | float], - noise_bounds: tuple[int | float], - signal_noise_gap: int | float, + signal_bounds: tuple[float], + noise_bounds: tuple[float], + signal_noise_gap: float, ) -> tuple[dict, dict]: """Create filter parameters for use with MNE's SSD implementation. @@ -452,14 +453,14 @@ def _compute_ssd( def fit_hpmax( self, - signal_bounds: tuple[int | float], - noise_bounds: tuple[int | float], + signal_bounds: tuple[float], + noise_bounds: tuple[float], n_harmonics: int = -1, indices: tuple[int] | None = None, rank: int | None = None, csd_method: str = "multitaper", n_fft: int | None = None, - mt_bandwidth: int | float = 5.0, + mt_bandwidth: float = 5.0, mt_adaptive: bool = True, mt_low_bias: bool = True, n_jobs: int = 1, @@ -563,7 +564,7 @@ def _compute_csd( self, csd_method: str, n_fft: int | None, - mt_bandwidth: int | float, + mt_bandwidth: float, mt_adaptive: bool, mt_low_bias: bool, n_jobs: int, @@ -837,7 +838,7 @@ def fit_transform_hpmax(self, *args: tuple, **kwargs: dict) -> np.ndarray: return self.transform() def get_transformed_data( - self, min_ratio: int | float = -np.inf, copy: bool = True + self, min_ratio: float = -np.inf, copy: bool = True ) -> np.ndarray: """Return the transformed data. diff --git a/src/pybispectra/utils/results.py b/src/pybispectra/utils/results.py index 8cf3569..184fdd6 100644 --- a/src/pybispectra/utils/results.py +++ b/src/pybispectra/utils/results.py @@ -5,9 +5,9 @@ import numpy as np from matplotlib.figure import Figure +from pybispectra.utils._defaults import _precision from pybispectra.utils._plot import _PlotCFC, _PlotGeneral, _PlotTDE, _PlotWaveShape from pybispectra.utils._utils import _int_like -from pybispectra.utils._defaults import _precision class _ResultsBase(ABC): @@ -316,7 +316,7 @@ def __init__( f2s: np.ndarray, times: np.ndarray | None = None, name: str = "CFC", - ) -> None: # noqa: D107 + ) -> None: super().__init__(data, (3, 4), name) self._sort_init_inputs(indices, f1s, f2s, times) @@ -368,13 +368,13 @@ def _get_compact_results_child(self) -> tuple[np.ndarray, tuple[tuple[int]]]: def plot( self, nodes: int | tuple[int] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_rows: int = 1, n_cols: int = 1, - major_tick_intervals: int | float = 5.0, - minor_tick_intervals: int | float = 1.0, + major_tick_intervals: float = 5.0, + minor_tick_intervals: float = 1.0, cbar_range: tuple[float] | list[tuple[float]] | None = None, show: bool = True, ) -> tuple[list[Figure], list[np.ndarray]]: @@ -509,9 +509,9 @@ class ResultsTDE(_ResultsBase): tau : ~numpy.ndarray, shape of [nodes, frequency_bands] Estimated time delay (in ms) for each connection and frequency band. - """ # noqa: E501 + """ - freq_bands: tuple[tuple[int | float]] = None + freq_bands: tuple[tuple[float]] = None _n_fbands: int = None def __repr__(self) -> str: @@ -535,9 +535,9 @@ def __init__( data: np.ndarray, indices: tuple[tuple[int]], times: np.ndarray, - freq_bands: tuple[tuple[int | float]] | None = None, + freq_bands: tuple[tuple[float]] | None = None, name: str = "TDE", - ) -> None: # noqa: D107 + ) -> None: super().__init__(data, (3,), name) self._sort_init_inputs(indices, times, freq_bands) @@ -553,10 +553,7 @@ def __init__( ) def _sort_init_inputs( - self, - indices: tuple[tuple[int]], - times: np.ndarray, - freq_bands: tuple[int | float], + self, indices: tuple[tuple[int]], times: np.ndarray, freq_bands: tuple[float] ) -> None: """Sort inputs to the object.""" super()._sort_indices_seeds_targets(indices) @@ -575,7 +572,7 @@ def _sort_times(self, times: np.ndarray) -> None: self.times = times - def _sort_freq_bands(self, freq_bands: tuple[tuple[int | float]]) -> None: + def _sort_freq_bands(self, freq_bands: tuple[tuple[float]]) -> None: """Sort ``freq_bands`` input.""" if freq_bands is not None: if not isinstance(freq_bands, tuple): @@ -621,11 +618,11 @@ def plot( self, nodes: int | tuple[int] | None = None, freq_bands: int | tuple[int] | None = None, - times: tuple[int | float] | None = None, + times: tuple[float] | None = None, n_rows: int = 1, n_cols: int = 1, - major_tick_intervals: int | float = 500.0, - minor_tick_intervals: int | float = 100.0, + major_tick_intervals: float = 500.0, + minor_tick_intervals: float = 100.0, show: bool = True, ) -> tuple[list[Figure], list[np.ndarray]]: """Plot the results. @@ -780,7 +777,7 @@ def __init__( f2s: np.ndarray, times: np.ndarray | None = None, name: str = "Waveshape", - ) -> None: # noqa: D107 + ) -> None: super().__init__(data, (3, 4), name) self._sort_init_inputs(indices, f1s, f2s, times) @@ -831,13 +828,13 @@ def get_results(self, copy: bool = True) -> np.ndarray: def plot( self, nodes: int | tuple[int] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_rows: int = 1, n_cols: int = 1, - major_tick_intervals: int | float = 5.0, - minor_tick_intervals: int | float = 1.0, + major_tick_intervals: float = 5.0, + minor_tick_intervals: float = 1.0, plot_absolute: bool = False, mirror_cbar_range: bool = True, cbar_range_abs: tuple[float] | list[tuple[float]] | None = None, @@ -1048,7 +1045,7 @@ def __init__( f2s: np.ndarray, times: np.ndarray | None = None, name: str = "General", - ) -> None: # noqa: D107 + ) -> None: super().__init__(data, (3, 4), name) self._sort_init_inputs(indices, f1s, f2s, times) @@ -1145,13 +1142,13 @@ def _get_compact_results_child(self) -> tuple[np.ndarray, tuple[tuple[int]]]: def plot( self, nodes: int | tuple[int] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, n_rows: int = 1, n_cols: int = 1, - major_tick_intervals: int | float = 5.0, - minor_tick_intervals: int | float = 1.0, + major_tick_intervals: float = 5.0, + minor_tick_intervals: float = 1.0, plot_absolute: bool = False, mirror_cbar_range: bool = True, cbar_range_abs: tuple[float] | list[tuple[float]] | None = None, @@ -1254,7 +1251,7 @@ def plot( ----- ``n_rows`` and ``n_cols`` of ``1`` will plot the results for each node on a new figure. - """ # noqa: E501 + """ figures, axes = self._plotting.plot( nodes=nodes, f1s=f1s, diff --git a/src/pybispectra/utils/utils.py b/src/pybispectra/utils/utils.py index aa7635b..0ba7134 100644 --- a/src/pybispectra/utils/utils.py +++ b/src/pybispectra/utils/utils.py @@ -1,13 +1,14 @@ """Public tools for handling data and processing results.""" +from collections.abc import Callable from multiprocessing import cpu_count -from typing import Callable -from packaging.version import Version -import pooch import numpy as np +import pooch import scipy as sp -from mne import time_frequency, __version__ as mne_version +from mne import __version__ as mne_version +from mne import time_frequency +from packaging.version import Version from pybispectra import __version__ as version from pybispectra.utils._defaults import _precision @@ -16,7 +17,7 @@ def compute_fft( data: np.ndarray, - sampling_freq: int | float, + sampling_freq: float, n_points: int | None = None, window: str = "hanning", n_jobs: int = 1, @@ -100,7 +101,7 @@ def compute_fft( def _compute_fft_input_checks( data: np.ndarray, - sampling_freq: int | float, + sampling_freq: float, n_points: int | None, window: str, n_jobs: int, @@ -156,13 +157,13 @@ def _compute_fft_input_checks( def compute_tfr( data: np.ndarray, - sampling_freq: int | float, + sampling_freq: float, freqs: np.ndarray, tfr_mode: str = "morlet", - n_cycles: np.ndarray | int | float = 7.0, + n_cycles: np.ndarray | float = 7.0, zero_mean_wavelets: bool | None = None, use_fft: bool = True, - multitaper_time_bandwidth: int | float = 4.0, + multitaper_time_bandwidth: float = 4.0, output: str = "power", n_jobs: int = 1, verbose: bool = True, @@ -206,10 +207,10 @@ def compute_tfr( output : ``"power"`` | ``"complex"`` (default ``"power"``) Type of TFR output to return. + .. versionadded:: 1.3 .. note:: If ``output = "complex"`` and ``tfr_mode = "multitaper"``, returning weights for each taper requires MNE version 1.10 or higher. - .. versionadded:: 1.3 n_jobs : int (default ``1``) Number of jobs to run in parallel. If ``-1``, all available CPUs are used. @@ -290,13 +291,13 @@ def compute_tfr( def _compute_tfr_input_checks( data: np.ndarray, - sampling_freq: int | float, + sampling_freq: float, freqs: np.ndarray, tfr_mode: str, - n_cycles: np.ndarray | int | float, + n_cycles: np.ndarray | float, zero_mean_wavelets: bool | None, use_fft: bool, - multitaper_time_bandwidth: int | float, + multitaper_time_bandwidth: float, output: str, n_jobs: int, verbose: bool, @@ -362,9 +363,10 @@ def _compute_tfr_input_checks( if not isinstance(use_fft, bool): raise TypeError("`use_fft` must be a bool.") - if tfr_mode == "multitaper": - if not isinstance(multitaper_time_bandwidth, _number_like): - raise TypeError("`multitaper_time_bandwidth` must be an int or a float.") + if tfr_mode == "multitaper" and not isinstance( + multitaper_time_bandwidth, _number_like + ): + raise TypeError("`multitaper_time_bandwidth` must be an int or a float.") outputs = ["power", "complex"] if not isinstance(output, str): @@ -394,7 +396,7 @@ def _compute_tfr_input_checks( return tfr_func, return_weights, n_jobs -def compute_rank(data: np.ndarray, sv_tol: int | float = 1e-5) -> int: +def compute_rank(data: np.ndarray, sv_tol: float = 1e-5) -> int: """Compute the minimum rank of data from non-zero singular values. Parameters @@ -536,7 +538,7 @@ def get_example_data_paths(name: str, verbose: bool = False) -> str: If the file is not found in the local cache (see :func:`pooch.os_cache` for the location), it will be downloaded automatically. """ - if name not in DATASETS.keys(): + if name not in DATASETS: raise ValueError(f"`name` must be one of: {list(DATASETS.keys())}") return _pooch.fetch(fname=DATASETS[name], progressbar=verbose) diff --git a/src/pybispectra/waveshape/waveshape.py b/src/pybispectra/waveshape/waveshape.py index 61bd186..79a9641 100644 --- a/src/pybispectra/waveshape/waveshape.py +++ b/src/pybispectra/waveshape/waveshape.py @@ -8,8 +8,8 @@ _compute_threenorm, _ProcessBispectrum, ) -from pybispectra.utils.results import ResultsWaveShape from pybispectra.utils._utils import _compute_in_parallel, _int_like +from pybispectra.utils.results import ResultsWaveShape np.seterr(divide="ignore", invalid="ignore") # no warning for NaN division @@ -78,7 +78,7 @@ class WaveShape(_ProcessBispectrum): References ---------- .. footbibliography:: - """ # noqa: E501 + """ _return_nonorm = False _return_threenorm = False @@ -86,9 +86,9 @@ class WaveShape(_ProcessBispectrum): def compute( self, indices: tuple[int] | None = None, - f1s: tuple[int | float] | None = None, - f2s: tuple[int | float] | None = None, - times: tuple[int | float] | None = None, + f1s: tuple[float] | None = None, + f2s: tuple[float] | None = None, + times: tuple[float] | None = None, norm: bool | tuple[bool] = True, n_jobs: int = 1, ) -> None: