From 29c9403616ad621dffd1ecebe57602c767b54c13 Mon Sep 17 00:00:00 2001 From: Joep Vanlier Date: Fri, 19 Jul 2024 17:16:38 +0200 Subject: [PATCH 1/3] ci: convert distribution to pyproject.toml --- setup.manifest => MANIFEST.in | 3 +- pyproject.toml | 74 +++++++++++++++++++++++++++++++++- release.md | 2 +- setup.cfg | 8 ---- setup.py | 76 ----------------------------------- 5 files changed, 76 insertions(+), 87 deletions(-) rename setup.manifest => MANIFEST.in (74%) delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/setup.manifest b/MANIFEST.in similarity index 74% rename from setup.manifest rename to MANIFEST.in index be4be2ccc..5fe91aff4 100644 --- a/setup.manifest +++ b/MANIFEST.in @@ -1,4 +1,5 @@ -include license.md readme.md +include license.md +include readme.md global-include *.npz global-include *.gb global-include *.csv diff --git a/pyproject.toml b/pyproject.toml index 26e8260dc..53447bb60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,58 @@ +[build-system] +requires = ["setuptools<69.3", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "lumicks.pylake" +dynamic = ["version"] +requires-python = ">= 3.10" +authors = [ + {name = "Lumicks B.V."}, + {email = "devteam@lumicks.com"}, +] +readme = {file="README.md", content-type = "text/markdown"} +license = {file = "license.md"} +keywords = ["optical tweezers", "kymographs", "data analysis", "lumicks"] +classifiers=[ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Physics", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", +] +dependencies = [ + "pytest>=3.5", + "h5py>=3.4, <4", + "numpy>=1.24, <2", # 1.24 is needed for dtype in vstack/hstack (Dec 18th, 2022) + "scipy>=1.9, <2", # 1.9.0 needed for lazy imports (July 29th, 2022) + "matplotlib>=3.8", + "tifffile>=2022.7.28", + "tabulate>=0.8.8, <0.9", + "cachetools>=3.1", + "deprecated>=1.2.8", + "scikit-learn>=0.18.0", + "scikit-image>=0.17.2", + "tqdm>=4.27.0", # 4.27.0 introduced tqdm.auto which auto-selects notebook or console +] +description = "Bluelake data analysis tools" + +[project.urls] +Homepage = "https://github.com/lumicks/pylake" +Documentation = "https://lumicks-pylake.readthedocs.io/en/stable/" +Source = "https://github.com/lumicks/pylake" + +[project.optional-dependencies] +notebook = [ + "notebook>=7", + "ipywidgets>=7.0.0", + "jupyter_client>=8", + "ipympl>=0.9.3", # Needed for mpl compatibility (previous vers are only up to mpl 3.7) +] + [tool.black] line-length = 100 target-version = ['py310'] @@ -20,6 +75,23 @@ exclude = ''' [tool.isort] profile = "black" line_length = 100 -py_version=310 +py_version = 310 length_sort_sections = ["stdlib", "thirdparty", "firstparty", "localfolder"] lines_between_sections = 1 + +[tool.pytest.ini_options] +minversion = "7.4" +addopts = "--doctest-modules --ignore=setup.py --ignore=docs/conf.py" +norecursedirs = ".* *.egg build docs/*" +filterwarnings = "error" + +[tool.setuptools.dynamic] +version = {attr = "lumicks.pylake.__about__.__version__"} + +[tool.setuptools.packages.find] +# Select the package(s) and data files to be included in the distribution. +# See https://setuptools.pypa.io/en/latest/userguide/package_discovery.html#custom-discovery +# Data files to be included (excluded) need to be selected in the file `MANIFEST.in`. Data files to +# be included in the wheel, need to be placed within the folder or a subfolder of the package(s) of +# the distribution. +include = ["lumicks*"] diff --git a/release.md b/release.md index fc1ee1c89..c82293e6f 100644 --- a/release.md +++ b/release.md @@ -13,7 +13,7 @@ Within the Pylake repo dir: - Update the date of the new release. - Review the changelog entries. Make sure everything is clear and informative for users. - Consider grouping some related entries if it makes sense. -- Bump the version number in `./lumicks/pylake/__about__.py`. +- Bump the version number in `./pyproject.toml`. - Commit changes with message "release: release Pylake v". - Check whether any dependencies of Pylake have changed and check if required packages do exist on anaconda: - `git diff v setup.py` to check changed dependencies. diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 9834250bc..000000000 --- a/setup.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[metadata] -license_file = license.md - -[tool:pytest] -minversion = 3.3 -addopts = --doctest-modules --ignore=setup.py --ignore=docs/conf.py -norecursedirs = .* *.egg build cpp* dist docs/* -filterwarnings = error diff --git a/setup.py b/setup.py deleted file mode 100644 index 36b968262..000000000 --- a/setup.py +++ /dev/null @@ -1,76 +0,0 @@ -import os -import sys - -from setuptools import PEP420PackageFinder, setup -from setuptools.command.egg_info import manifest_maker - -if sys.version_info[:2] < (3, 10): - print("Python >= 3.10 is required.") - sys.exit(-1) - - -def about(package): - ret = {} - filename = os.path.join(os.path.dirname(__file__), package.replace(".", "/"), "__about__.py") - with open(filename, "rb") as file: - exec(compile(file.read(), filename, "exec"), ret) - return ret - - -def read(filename): - if not os.path.exists(filename): - return "" - - with open(filename) as f: - return f.read() - - -info = about("lumicks.pylake") -manifest_maker.template = "setup.manifest" -setup( - name=info["__title__"], - version=info["__version__"], - description=info["__summary__"], - long_description=read("readme.md"), - long_description_content_type="text/markdown", - url=info["__url__"], - license=info["__license__"], - keywords="", - author=info["__author__"], - author_email=info["__email__"], - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Science/Research", - "Topic :: Scientific/Engineering :: Physics", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: Implementation :: CPython", - ], - packages=PEP420PackageFinder.find(include=["lumicks.*"]), - include_package_data=True, - python_requires=">=3.10", - install_requires=[ - "pytest>=3.5", - "h5py>=3.4, <4", - "numpy>=1.24, <2", # 1.24 is needed for dtype in vstack/hstack (Dec 18th, 2022) - "scipy>=1.9, <2", # 1.9.0 needed for lazy imports (July 29th, 2022) - "matplotlib>=3.8", - "tifffile>=2022.7.28", - "tabulate>=0.8.8, <0.9", - "cachetools>=3.1", - "deprecated>=1.2.8", - "scikit-learn>=0.18.0", - "scikit-image>=0.17.2", - "tqdm>=4.27.0", # 4.27.0 introduced tqdm.auto which auto-selects notebook or console - ], - extras_require={ - "notebook": [ - "notebook>=7", - "ipywidgets>=7.0.0", - "jupyter_client>=8", - "ipympl>=0.9.3", # Needed for mpl compatibility (previous vers are only up to mpl 3.7) - ], - }, - zip_safe=False, -) From 5806e0cc2274a9c909625c41676c02555292ba58 Mon Sep 17 00:00:00 2001 From: Joep Vanlier Date: Fri, 19 Jul 2024 19:44:07 +0200 Subject: [PATCH 2/3] ci: bump `black` and add `pre-commit` hook --- .github/workflows/pylake_test.yml | 2 +- .pre-commit-config.yaml | 24 ++++++++++++++++++++++++ contributing.md | 14 ++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/pylake_test.yml b/.github/workflows/pylake_test.yml index 91a6713be..3c08c6ef7 100644 --- a/.github/workflows/pylake_test.yml +++ b/.github/workflows/pylake_test.yml @@ -36,7 +36,7 @@ jobs: run: python -c "import lumicks.pylake as lk; lk.benchmark(repeat=1)" - name: Black run: | - pip install black==23.7.0 isort==5.12.0 + pip install black==24.4.2 isort==5.13.2 black --check --diff --color . isort --check-only --diff . - name: flake8 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..a4e4f558e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +repos: +- repo: https://github.com/psf/black + rev: 24.4.2 + hooks: + - id: black +- repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: end-of-file-fixer + exclude: ^.*\.png$ ^.*\.gif$ + - id: requirements-txt-fixer + - id: trailing-whitespace + exclude: ^.*\.png$ ^.*\.gif$ +- repo: https://github.com/pycqa/flake8 + rev: 7.1.0 + hooks: + - id: flake8 + language_version: python3 + additional_dependencies: + - flake8-bugbear==24.4.26 diff --git a/contributing.md b/contributing.md index 25bc1f4b0..33d1aa41f 100644 --- a/contributing.md +++ b/contributing.md @@ -59,3 +59,17 @@ Code and documentation contributions will generally proceed through a Pull Reque - Please set up your editor to follow PEP8 (remove trailing white space, no tabs, etc.). Use [black](https://github.com/psf/black) to format your code. - All public functions and classes require an informative docstring. Document these using the [numpydoc](https://numpydoc.readthedocs.io/en/latest/format.html) style. - Features should ideally be grouped by category in their own folder, with implementational details in a sub-folder named `detail`. Tests for each specific category should be placed in a sub-folder `tests`. + +### Installing pre-commit hooks + +To help with formatting and code-style consider installing the pre-commit hooks. +These will check the formatting whenever you commit. +Install `pre-commit` with: + + pip install pre-commit + +Next, set up the hook with:: + + pre-commit install + +That's all there is to it. From e40a9f28d34824cbfb382d27028f8b620016ee44 Mon Sep 17 00:00:00 2001 From: black Date: Fri, 19 Jul 2024 20:13:41 +0200 Subject: [PATCH 3/3] ci: update black --- docs/conf.py | 2 +- lumicks/pylake/calibration.py | 8 +++++--- lumicks/pylake/detail/mixin.py | 1 + lumicks/pylake/detail/tests/test_bead_crop.py | 8 +++++--- .../fitting/detail/model_implementation.py | 16 +++------------ .../force_calibration/calibration_models.py | 6 +++--- lumicks/pylake/kymotracker/kymotracker.py | 16 +++++++++------ lumicks/pylake/kymotracker/tests/test_io.py | 20 +++++++++++-------- lumicks/pylake/nb_widgets/image_editing.py | 4 ++-- .../pylake/nb_widgets/kymotracker_widgets.py | 8 +++++--- lumicks/pylake/population/detail/fit_info.py | 1 + .../test_kymo_plotting.py | 12 +++++++---- .../test_kymo_slice_crop.py | 20 +++++++++---------- .../tests/test_imaging_confocal/test_scan.py | 8 +++++--- .../test_scan_slice_crop.py | 16 +++++++-------- 15 files changed, 78 insertions(+), 68 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 390e55384..5c18c0b26 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -256,7 +256,7 @@ # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. "preamble": r"\definecolor{VerbatimBorderColor}{rgb}{1,1,1}" - r"\usepackage{etoolbox}\patchcmd{\thebibliography}{\section*{\refname}}{}{}{}" + r"\usepackage{etoolbox}\patchcmd{\thebibliography}{\section*{\refname}}{}{}{}", # Latex figure (float) alignment # 'figure_align': 'htbp', } diff --git a/lumicks/pylake/calibration.py b/lumicks/pylake/calibration.py index 10ecbefce..e82829af3 100644 --- a/lumicks/pylake/calibration.py +++ b/lumicks/pylake/calibration.py @@ -132,9 +132,11 @@ def format_timestamp(timestamp): item.kind, f"{item.stiffness:.2f}" if item.stiffness else "N/A", f"{item.force_sensitivity:.2f}" if item.force_sensitivity else "N/A", - f"{item.displacement_sensitivity:.2f}" - if item.displacement_sensitivity - else "N/A", + ( + f"{item.displacement_sensitivity:.2f}" + if item.displacement_sensitivity + else "N/A" + ), item.hydrodynamically_correct, item.distance_to_surface is not None, bool( diff --git a/lumicks/pylake/detail/mixin.py b/lumicks/pylake/detail/mixin.py index afe8bf283..f10e73ad4 100644 --- a/lumicks/pylake/detail/mixin.py +++ b/lumicks/pylake/detail/mixin.py @@ -1,4 +1,5 @@ """Mixin class which add properties for predefined channels""" + from ..channel import Slice, empty_slice diff --git a/lumicks/pylake/detail/tests/test_bead_crop.py b/lumicks/pylake/detail/tests/test_bead_crop.py index f885d13bc..4f2eb01d6 100644 --- a/lumicks/pylake/detail/tests/test_bead_crop.py +++ b/lumicks/pylake/detail/tests/test_bead_crop.py @@ -31,8 +31,10 @@ def test_bead_cropping_allow_negative_beads(filename, ref_edges, ref_edges_no_ne # because the fluorescence typically tails out wide. np.testing.assert_equal(edges, ref_edges) - with nullcontext() if ref_edges_no_negative else pytest.raises( - RuntimeError, match="Did not find two beads" + with ( + nullcontext() + if ref_edges_no_negative + else pytest.raises(RuntimeError, match="Did not find two beads") ): edges = find_beads_brightness( np.atleast_2d(data["green"]).T, @@ -50,7 +52,7 @@ def test_bead_cropping_failure(): def test_plotting(): - data = np.load(pathlib.Path(__file__).parent / "data" / f"kymo_sum0.npz") + data = np.load(pathlib.Path(__file__).parent / "data" / "kymo_sum0.npz") for allow_negative in (False, True): edges = find_beads_brightness( np.atleast_2d(data["green"]).T, diff --git a/lumicks/pylake/fitting/detail/model_implementation.py b/lumicks/pylake/fitting/detail/model_implementation.py index a6b33566c..051b1ddaa 100644 --- a/lumicks/pylake/fitting/detail/model_implementation.py +++ b/lumicks/pylake/fitting/detail/model_implementation.py @@ -889,16 +889,8 @@ def ewlc_marko_siggia_force_jac(d, Lp, Lc, St, kT=4.11): denom1 = Lc**3 * (Lp * St + kT) ** 2 denom2 = Lc * (Lp**2 * St**2 + 2.0 * Lp * St * kT + kT**2) dkT = d * kT - dc_dLc = ( - St**3 * dkT * (1.5 * Lc**2 - 4.5 * Lc * d + 3.0 * d**2) / (Lc**4 * (Lp * St + kT)) - ) - dc_dSt = ( - -(St**2) - * dkT - * (2 * Lp * St + 3 * kT) - * (1.5 * Lc**2 - 2.25 * Lc * d + d**2) - / denom1 - ) + dc_dLc = St**3 * dkT * (1.5 * Lc**2 - 4.5 * Lc * d + 3.0 * d**2) / (Lc**4 * (Lp * St + kT)) + dc_dSt = -(St**2) * dkT * (2 * Lp * St + 3 * kT) * (1.5 * Lc**2 - 2.25 * Lc * d + d**2) / denom1 dc_dLp = St**4 * dkT * (1.5 * Lc**2 - 2.25 * Lc * d + d**2) / denom1 dc_dkT = -Lp * St**4 * d * (1.5 * Lc**2 - 2.25 * Lc * d + d**2) / denom1 db_dLc = ( @@ -1287,9 +1279,7 @@ def ewlc_marko_siggia_distance_derivative(f, Lp, Lc, St, kT=4.11): ) / (St**3 * kT) ) - db_df = ( - Lc**2 * (4 * f * Lp * St + 6 * f * kT + 2 * Lp * St**2 + 4.5 * St * kT) / (St**2 * kT) - ) + db_df = Lc**2 * (4 * f * Lp * St + 6 * f * kT + 2 * Lp * St**2 + 4.5 * St * kT) / (St**2 * kT) da_df = -Lc * Lp / kT - 3 * Lc / St return total_dy_da * da_df + total_dy_db * db_df + total_dy_dc * dc_df diff --git a/lumicks/pylake/force_calibration/calibration_models.py b/lumicks/pylake/force_calibration/calibration_models.py index 32a3bbc79..d22a9715c 100644 --- a/lumicks/pylake/force_calibration/calibration_models.py +++ b/lumicks/pylake/force_calibration/calibration_models.py @@ -866,9 +866,9 @@ def __init__( bead_radius=self.bead_diameter * 1e-6 / 2.0, # um diameter -> m radius rho_sample=self.rho_sample, rho_bead=self.rho_bead, - distance_to_surface=None - if self.distance_to_surface is None - else self.distance_to_surface * 1e-6, # um => m + distance_to_surface=( + None if self.distance_to_surface is None else self.distance_to_surface * 1e-6 + ), # um => m ) else: self._theoretical_driving_power_model = partial( diff --git a/lumicks/pylake/kymotracker/kymotracker.py b/lumicks/pylake/kymotracker/kymotracker.py index 4b21d6b24..e2bb221a5 100644 --- a/lumicks/pylake/kymotracker/kymotracker.py +++ b/lumicks/pylake/kymotracker/kymotracker.py @@ -189,9 +189,11 @@ def track_greedy( bias_correction=bias_correction, filter_width=filter_width / kymograph.pixelsize_um[0] if filter_width is not None else 0.5, adjacency_half_width=half_width_pixels if adjacency_filter else None, - rect=_to_pixel_rect(rect, kymograph.pixelsize[0], kymograph.line_time_seconds) - if rect - else None, + rect=( + _to_pixel_rect(rect, kymograph.pixelsize[0], kymograph.line_time_seconds) + if rect + else None + ), ) if not peaks: @@ -389,9 +391,11 @@ def minimum_observable_time(track, min_length, min_duration): track._with_minimum_time( max( # We can't unfilter tracks. - track._minimum_observable_duration - if track._minimum_observable_duration is not None - else 0, + ( + track._minimum_observable_duration + if track._minimum_observable_duration is not None + else 0 + ), minimum_observable_time(track, minimum_length, minimum_duration), ) ) diff --git a/lumicks/pylake/kymotracker/tests/test_io.py b/lumicks/pylake/kymotracker/tests/test_io.py index 429337ce9..d1b42eed1 100644 --- a/lumicks/pylake/kymotracker/tests/test_io.py +++ b/lumicks/pylake/kymotracker/tests/test_io.py @@ -198,13 +198,17 @@ def test_csv_version(version, read_with_version): ) testfile = Path(__file__).parent / f"./data/tracks_v{version}.csv" - with pytest.warns( - RuntimeWarning, - match=( - "This CSV file is from a version in which the minimum observable track duration " - "was incorrectly rounded to an integer." - ), - ) if version == 3 else contextlib.nullcontext(): + with ( + pytest.warns( + RuntimeWarning, + match=( + "This CSV file is from a version in which the minimum observable track duration " + "was incorrectly rounded to an integer." + ), + ) + if version == 3 + else contextlib.nullcontext() + ): imported_tracks = import_kymotrackgroup_from_csv(testfile, kymo, "red", delimiter=";") data, pylake_version, csv_version = _read_txt(testfile, ";") @@ -228,7 +232,7 @@ def test_bad_csv(filename, blank_kymo): def test_min_obs_csv_regression(tmpdir_factory, blank_kymo): """This tests a regression where saving a freshly imported older file does not function""" - testfile = Path(__file__).parent / f"./data/tracks_v0.csv" + testfile = Path(__file__).parent / "./data/tracks_v0.csv" imported_tracks = import_kymotrackgroup_from_csv(testfile, blank_kymo, "red", delimiter=";") out_file = f"{tmpdir_factory.mktemp('pylake')}/no_min_lengths.csv" diff --git a/lumicks/pylake/nb_widgets/image_editing.py b/lumicks/pylake/nb_widgets/image_editing.py index 367a4cf24..fe3d29043 100644 --- a/lumicks/pylake/nb_widgets/image_editing.py +++ b/lumicks/pylake/nb_widgets/image_editing.py @@ -59,8 +59,8 @@ def __init__( self.channel = channel self.current_frame = frame self.num_frames = self._current_image.num_frames - self.make_title = ( - lambda: make_image_title(self._current_image, self.current_frame, show_name=False) + self.make_title = lambda: ( + make_image_title(self._current_image, self.current_frame, show_name=False) if show_title else (lambda: "") ) diff --git a/lumicks/pylake/nb_widgets/kymotracker_widgets.py b/lumicks/pylake/nb_widgets/kymotracker_widgets.py index d0f6c4f8d..83b3f47e9 100644 --- a/lumicks/pylake/nb_widgets/kymotracker_widgets.py +++ b/lumicks/pylake/nb_widgets/kymotracker_widgets.py @@ -760,9 +760,11 @@ def _create_algorithm_sliders(self): def threshold_slider_callback(change): self._set_label( "warning", - "" - if change["new"] > min_threshold - else f"Tracking with threshold of {change['new']} may be slow.", + ( + "" + if change["new"] > min_threshold + else f"Tracking with threshold of {change['new']} may be slow." + ), ) threshold_slider.observe( diff --git a/lumicks/pylake/population/detail/fit_info.py b/lumicks/pylake/population/detail/fit_info.py index 06ecc56b3..5905f952b 100644 --- a/lumicks/pylake/population/detail/fit_info.py +++ b/lumicks/pylake/population/detail/fit_info.py @@ -31,6 +31,7 @@ class PopulationFitInfo: log_likelihood: float log of the maximized value of the likelihood function of the fitted data """ + converged: bool n_iter: int bic: float diff --git a/lumicks/pylake/tests/test_imaging_confocal/test_kymo_plotting.py b/lumicks/pylake/tests/test_imaging_confocal/test_kymo_plotting.py index faec3ec66..58a85223e 100644 --- a/lumicks/pylake/tests/test_imaging_confocal/test_kymo_plotting.py +++ b/lumicks/pylake/tests/test_imaging_confocal/test_kymo_plotting.py @@ -290,10 +290,14 @@ def process_binning(px_per_bin, axis): for px_per_bin in range(1, ref.image.shape[0] + 1): ref_counts, ref_bin_widths, msg = process_binning(px_per_bin, "position") - with pytest.warns( - UserWarning, - match=msg, - ) if msg else nullcontext(): + with ( + pytest.warns( + UserWarning, + match=msg, + ) + if msg + else nullcontext() + ): kymo.plot_with_position_histogram(color_channel="red", pixels_per_bin=px_per_bin) counts, bin_widths = get_hist_data("position") diff --git a/lumicks/pylake/tests/test_imaging_confocal/test_kymo_slice_crop.py b/lumicks/pylake/tests/test_imaging_confocal/test_kymo_slice_crop.py index a8bfb504c..8e7eeb32d 100644 --- a/lumicks/pylake/tests/test_imaging_confocal/test_kymo_slice_crop.py +++ b/lumicks/pylake/tests/test_imaging_confocal/test_kymo_slice_crop.py @@ -1,5 +1,3 @@ -import pathlib - import numpy as np import pytest @@ -39,43 +37,43 @@ def test_kymo_slicing(test_kymo): np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, :, 0]) num_lines = 2 - sliced = kymo["0s":f"{num_lines * line_time}s"] + sliced = kymo["0s" :f"{num_lines * line_time}s"] assert sliced.get_image("red").shape == (ref_pixels, num_lines) assert sliced.shape == (ref_pixels, num_lines, 3) np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, :num_lines, 0]) - sliced = kymo["0s":f"-{line_time * 0.6}s"] + sliced = kymo["0s" :f"-{line_time * 0.6}s"] assert sliced.get_image("red").shape == (ref_pixels, ref_lines - 1) np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, :-1, 0]) - sliced = kymo["0s":f"-{2 * line_time}s"] + sliced = kymo["0s" :f"-{2 * line_time}s"] assert sliced.get_image("red").shape == (ref_pixels, ref_lines - 2) np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, : (ref_lines - 2), 0]) # get a sliver of the next frame # stop needs to be > halfway the deadtime between lines - sliced = kymo["0s":f"-{2 * line_time - deadtime_slice_offset}s"] + sliced = kymo["0s" :f"-{2 * line_time - deadtime_slice_offset}s"] assert sliced.get_image("red").shape == (ref_pixels, ref_lines - 1) np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, :-1, 0]) # Two full frames - sliced = kymo["0s":f"{2 * line_time}s"] + sliced = kymo["0s" :f"{2 * line_time}s"] assert sliced.get_image("red").shape == (ref_pixels, 2) np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, :2, 0]) # Two full frames plus a bit - sliced = kymo["0s":f"{2 * scan_time + 2 * dead_time + deadtime_slice_offset}s"] + sliced = kymo["0s" :f"{2 * scan_time + 2 * dead_time + deadtime_slice_offset}s"] assert sliced.get_image("red").shape == (ref_pixels, 3) np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, :3, 0]) # slice from deadtime before first line until deadtime after first line - sliced = kymo[f"{scan_time + dead_time / 2}s":f"{2 * line_time - dead_time / 2}s"] + sliced = kymo[f"{scan_time + dead_time / 2}s" :f"{2 * line_time - dead_time / 2}s"] assert sliced.get_image("red").shape == (ref_pixels, 1) assert sliced.shape == (ref_pixels, 1, 3) np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, 1:2, 0]) # slice over entire kymo - sliced = kymo["0s":f"{line_time * (ref.metadata.lines_per_frame + 1)}s"] + sliced = kymo["0s" :f"{line_time * (ref.metadata.lines_per_frame + 1)}s"] assert sliced.get_image("red").shape == (ref_pixels, ref_lines) assert sliced.shape == (ref_pixels, ref_lines, 3) np.testing.assert_allclose(sliced.get_image("red").data, ref.image[:, :, 0]) @@ -245,7 +243,7 @@ def test_kymo_slice_crop(cropping_kymo): dead_time = (ref.timestamps.dt * ref.infowave.line_padding * 2) * 1e-9 line_time = scan_time + dead_time - sliced_cropped = kymo[f"{line_time}s":f"{5 * line_time}s"].crop_by_distance( + sliced_cropped = kymo[f"{line_time}s" :f"{5 * line_time}s"].crop_by_distance( 2 * px_size, 4 * px_size ) np.testing.assert_equal(sliced_cropped.timestamps, ref.timestamps.data[2:4, 1:5]) diff --git a/lumicks/pylake/tests/test_imaging_confocal/test_scan.py b/lumicks/pylake/tests/test_imaging_confocal/test_scan.py index baf9b0942..bf529496d 100644 --- a/lumicks/pylake/tests/test_imaging_confocal/test_scan.py +++ b/lumicks/pylake/tests/test_imaging_confocal/test_scan.py @@ -29,9 +29,11 @@ def test_scan_attrs(test_scans, test_scans_multiframe): np.testing.assert_equal( scan.frame_timestamp_ranges(include_dead_time=True), - ref.timestamps.timestamp_ranges # For the single frame case, there is no dead time - if scan.num_frames == 1 - else ref.timestamps.timestamp_ranges_deadtime, + ( + ref.timestamps.timestamp_ranges # For the single frame case, there is no dead time + if scan.num_frames == 1 + else ref.timestamps.timestamp_ranges_deadtime + ), ) np.testing.assert_equal(scan.frame_timestamp_ranges(), ref.timestamps.timestamp_ranges) diff --git a/lumicks/pylake/tests/test_imaging_confocal/test_scan_slice_crop.py b/lumicks/pylake/tests/test_imaging_confocal/test_scan_slice_crop.py index 7e4f8d21c..398a96a44 100644 --- a/lumicks/pylake/tests/test_imaging_confocal/test_scan_slice_crop.py +++ b/lumicks/pylake/tests/test_imaging_confocal/test_scan_slice_crop.py @@ -255,22 +255,22 @@ def test_scan_slicing_by_time(test_scan_slicing): wiggle = 0.01 # start of frame 2, until frame 2 signal stop - assert isinstance(multi_frame[f"{rng[2, 0]}s":f"{rng[2, 1]}s"], EmptyScan) + assert isinstance(multi_frame[f"{rng[2, 0]}s" :f"{rng[2, 1]}s"], EmptyScan) # start of frame 2, just over frame 2 signal stop - sliced = multi_frame[f"{rng[2, 0]}s":f"{rng[2, 1] + wiggle}s"] + sliced = multi_frame[f"{rng[2, 0]}s" :f"{rng[2, 1] + wiggle}s"] np.testing.assert_equal(sliced.get_image("rgb"), ref.image[2]) # start of frame 2, until frame 3 signal stop - sliced = multi_frame[f"{rng[2, 0]}s":f"{rng[3, 1]}s"] + sliced = multi_frame[f"{rng[2, 0]}s" :f"{rng[3, 1]}s"] np.testing.assert_equal(sliced.get_image("rgb"), ref.image[2]) # start of frame 2, just over frame 3 signal stop - sliced = multi_frame[f"{rng[2, 0]}s":f"{rng[3, 1] + wiggle}s"] + sliced = multi_frame[f"{rng[2, 0]}s" :f"{rng[3, 1] + wiggle}s"] np.testing.assert_equal(sliced.get_image("rgb"), ref.image[2:4]) # start of frame 2, until start of frame 4 - sliced = multi_frame[f"{rng[2, 0]}s":f"{rng[4, 0]}s"] + sliced = multi_frame[f"{rng[2, 0]}s" :f"{rng[4, 0]}s"] np.testing.assert_equal(sliced.get_image("rgb"), ref.image[2:4]) # from start of frame 2 @@ -332,15 +332,15 @@ def test_scan_slicing_by_time_iterative(test_scan_slicing): wiggle = 0.01 # first slice frame 2 through 5 (inclusive) - first_slice = multi_frame[f"{rng[2, 0]}s":f"{rng[5, 1] + wiggle}s"] + first_slice = multi_frame[f"{rng[2, 0]}s" :f"{rng[5, 1] + wiggle}s"] ref_sliced = ref.image[2:6] # start of frame 1, just over frame 3 signal stop - sliced = first_slice[f"{rng[1, 0]}s":f"{rng[3, 1] + wiggle}s"] + sliced = first_slice[f"{rng[1, 0]}s" :f"{rng[3, 1] + wiggle}s"] np.testing.assert_equal(sliced.get_image("rgb"), ref_sliced[1:4]) # start of frame 1, until frame 3 signal stop - sliced = first_slice[f"{rng[1, 0]}s":f"{rng[3, 1]}s"] + sliced = first_slice[f"{rng[1, 0]}s" :f"{rng[3, 1]}s"] np.testing.assert_equal(sliced.get_image("rgb"), ref_sliced[1:3]) # from start of frame 1