lbm_suite2p_python 3.0.3__tar.gz → 3.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {lbm_suite2p_python-3.0.3/lbm_suite2p_python.egg-info → lbm_suite2p_python-3.0.5}/PKG-INFO +2 -2
  2. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/__init__.py +2 -0
  3. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/run_lsp.py +99 -27
  4. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5/lbm_suite2p_python.egg-info}/PKG-INFO +2 -2
  5. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python.egg-info/requires.txt +1 -1
  6. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/pyproject.toml +106 -106
  7. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/LICENSE.md +0 -0
  8. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/MANIFEST.in +0 -0
  9. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/README.md +0 -0
  10. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/__main__.py +0 -0
  11. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/_benchmarking.py +0 -0
  12. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/cellpose.py +0 -0
  13. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/cli.py +0 -0
  14. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/conversion.py +0 -0
  15. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/db_settings.py +0 -0
  16. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/default_ops.py +0 -0
  17. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/grid_search.py +0 -0
  18. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/gui.py +0 -0
  19. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/merging.py +0 -0
  20. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/postprocessing.py +0 -0
  21. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/utils.py +0 -0
  22. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/volume.py +0 -0
  23. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python/zplane.py +0 -0
  24. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python.egg-info/SOURCES.txt +0 -0
  25. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python.egg-info/dependency_links.txt +0 -0
  26. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python.egg-info/entry_points.txt +0 -0
  27. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/lbm_suite2p_python.egg-info/top_level.txt +0 -0
  28. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/setup.cfg +0 -0
  29. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/tests/test_frame_count_aliases.py +0 -0
  30. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/tests/test_pipeline_parameters.py +0 -0
  31. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/tests/test_refactored_pipeline.py +0 -0
  32. {lbm_suite2p_python-3.0.3 → lbm_suite2p_python-3.0.5}/tests/test_run_volume.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lbm_suite2p_python
3
- Version: 3.0.3
3
+ Version: 3.0.5
4
4
  Summary: Calcium Imaging Pipeline built with Suite2p, Cellpose and Rastermap
5
5
  License-Expression: BSD-3-Clause
6
6
  Project-URL: homepage, https://github.com/MillerBrainObservatory/LBM-Suite2p-Python
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
11
11
  Requires-Python: <3.14,>=3.12.7
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.md
14
- Requires-Dist: mbo_utilities>=3.0.2
14
+ Requires-Dist: mbo_utilities>=3.0.3
15
15
  Requires-Dist: suite2p>=1.0.0.1
16
16
  Requires-Dist: setuptools<81
17
17
  Provides-Extra: rastermap
@@ -7,6 +7,7 @@ from lbm_suite2p_python.run_lsp import (
7
7
  run_plane,
8
8
  add_processing_step,
9
9
  generate_plane_dirname,
10
+ compute_enhanced_mean_image
10
11
  )
11
12
 
12
13
  from lbm_suite2p_python.cellpose import (
@@ -95,6 +96,7 @@ __all__ = [
95
96
  "default_ops",
96
97
  "add_processing_step",
97
98
  "generate_plane_dirname",
99
+ "compute_enhanced_mean_image"
98
100
 
99
101
  # Cellpose / HITL Workflow
100
102
  "train_cellpose",
@@ -101,7 +101,7 @@ def _call_upstream_pipeline(ops, f_reg, f_raw, f_reg_chan2, f_raw_chan2,
101
101
  return ops
102
102
 
103
103
 
104
- def _compute_enhanced_mean_image(img, ops):
104
+ def compute_enhanced_mean_image(img, ops):
105
105
  """Compat shim for upstream's removal of `compute_enhanced_mean_image`.
106
106
 
107
107
  Upstream suite2p replaced `compute_enhanced_mean_image(img, ops)` with
@@ -237,7 +237,6 @@ def _copy_if_needed(src: Path, dst: Path, *, overwrite_empty: bool = True) -> bo
237
237
  if dst.exists():
238
238
  if not (overwrite_empty and dst.stat().st_size == 0):
239
239
  return False
240
- print(f" Copying {src.name} from {src.parent} -> {dst.parent}")
241
240
  shutil.copy2(src, dst)
242
241
  return True
243
242
 
@@ -263,6 +262,7 @@ def _stage_source_into_plane_dir(
263
262
  plane_dir = Path(plane_dir)
264
263
  plane_dir.mkdir(parents=True, exist_ok=True)
265
264
 
265
+ print(f" Staging plane outputs: {src_dir.name} -> {plane_dir.name}")
266
266
  _copy_if_needed(src_dir / "ops.npy", plane_dir / "ops.npy")
267
267
  for fname in _DETECTION_OUTPUT_FILES:
268
268
  _copy_if_needed(src_dir / fname, plane_dir / fname)
@@ -1729,7 +1729,7 @@ def run_plane_bin(ops) -> bool:
1729
1729
  print(" Computed meanImg from binary")
1730
1730
 
1731
1731
  if "meanImgE" not in ops and "meanImg" in ops:
1732
- ops["meanImgE"] = _compute_enhanced_mean_image(
1732
+ ops["meanImgE"] = compute_enhanced_mean_image(
1733
1733
  ops["meanImg"].astype(np.float32), ops
1734
1734
  )
1735
1735
  print(" Computed meanImgE from meanImg")
@@ -1791,7 +1791,7 @@ def run_plane_bin(ops) -> bool:
1791
1791
 
1792
1792
  # ensure meanImgE is always present in final ops (safety net)
1793
1793
  if "meanImgE" not in ops and "meanImg" in ops:
1794
- ops["meanImgE"] = _compute_enhanced_mean_image(
1794
+ ops["meanImgE"] = compute_enhanced_mean_image(
1795
1795
  ops["meanImg"].astype(np.float32), ops
1796
1796
  )
1797
1797
 
@@ -2026,6 +2026,10 @@ def run_plane(
2026
2026
  )
2027
2027
 
2028
2028
  existing_ops = np.load(src_dir / "ops.npy", allow_pickle=True).item()
2029
+ # remember the original acquisition source before the merge below
2030
+ # overwrites data_path with the staged binary path. needed by
2031
+ # force_reg path when the source has no data_raw.bin.
2032
+ original_data_path = existing_ops.get("data_path")
2029
2033
  metadata = {
2030
2034
  k: v
2031
2035
  for k, v in existing_ops.items()
@@ -2073,20 +2077,71 @@ def run_plane(
2073
2077
  "data_path": str(input_path.resolve()),
2074
2078
  }
2075
2079
 
2076
- # registration would need to write to data.bin, but data.bin
2077
- # lives at the source dir running it would clobber the user's
2078
- # source binary. force detection-only; user can re-register from
2079
- # the original tiff/zarr if they want fresh registration.
2080
- if ops_user.get("do_registration", 1):
2081
- logger.warning(
2082
- "do_registration=1 ignored when staging from an existing "
2083
- "registered binary into a different save_path — running "
2084
- "registration would clobber the source data.bin. Forcing "
2085
- "do_registration=0 (detection-only)."
2086
- )
2087
- ops["do_registration"] = 0
2080
+ if not force_reg:
2081
+ # registration would need to write to data.bin, but data.bin
2082
+ # lives at the source dir running it would clobber the user's
2083
+ # source binary. force detection-only; user can re-register
2084
+ # from the original tiff/zarr by passing force_reg=True (Force
2085
+ # in the GUI), which routes writes into the new plane_dir.
2086
+ if ops_user.get("do_registration", 1):
2087
+ logger.warning(
2088
+ "do_registration ignored when staging into a different "
2089
+ "save_path — running registration would clobber the "
2090
+ "source data.bin. Forcing do_registration=0 "
2091
+ "(detection-only). Pass force_reg=True (Force in the "
2092
+ "GUI) to re-register into the new save_path."
2093
+ )
2094
+ ops["do_registration"] = 0
2088
2095
 
2089
2096
  _stage_source_into_plane_dir(src_dir, plane_dir, ops)
2097
+
2098
+ if force_reg:
2099
+ # writes go to plane_dir/data.bin — discard the source pointer
2100
+ # that _stage_source_into_plane_dir set.
2101
+ ops.pop("reg_file", None)
2102
+ # existing_ops carries a `raw_file` path from the original
2103
+ # run; if keep_raw=False removed the file, the string is
2104
+ # still present but stale. existence-check, don't trust the
2105
+ # string alone.
2106
+ _raw = ops.get("raw_file")
2107
+ if not _raw or not Path(_raw).exists():
2108
+ import shutil
2109
+ target_raw = plane_dir / "data_raw.bin"
2110
+ # prefer the original acquisition (tiff/zarr) when it's
2111
+ # still on disk — avoids re-registering already-
2112
+ # registered data. Skip when it points at the same .bin
2113
+ # the user just loaded (no improvement, and imread of a
2114
+ # stale data_path could be wrong).
2115
+ use_original = (
2116
+ bool(original_data_path)
2117
+ and Path(original_data_path).exists()
2118
+ and Path(original_data_path).resolve() != input_path.resolve()
2119
+ )
2120
+ if use_original:
2121
+ print(
2122
+ f" Force registration: rewriting data_raw.bin from "
2123
+ f"{Path(original_data_path).name}"
2124
+ )
2125
+ file = imread(Path(original_data_path), **reader_kwargs)
2126
+ if hasattr(file, "metadata"):
2127
+ metadata = dict(file.metadata)
2128
+ else:
2129
+ metadata = get_metadata(Path(original_data_path))
2130
+ skip_imwrite = False
2131
+ else:
2132
+ # original acquisition is gone (or IS the input).
2133
+ # seed data_raw.bin from the staged data.bin so
2134
+ # registration has frames to work with. Re-registers
2135
+ # already-registered data (near-zero shifts) — fine
2136
+ # for detection / bad-frame re-runs.
2137
+ print(
2138
+ f" Force registration: original acquisition "
2139
+ f"unavailable; seeding data_raw.bin from "
2140
+ f"{input_path.name} (re-registering already-"
2141
+ f"registered data)"
2142
+ )
2143
+ shutil.copy2(input_path, target_raw)
2144
+ ops["raw_file"] = str(target_raw)
2090
2145
  else:
2091
2146
  skip_imwrite = False
2092
2147
 
@@ -2569,17 +2624,6 @@ def run_plane(
2569
2624
  )
2570
2625
  np.save(plane_dir / "dff.npy", dff)
2571
2626
 
2572
- # Record the dF/F params that actually drew the dff.npy +
2573
- # figures. These live as top-level ops keys (NOT in the suite2p
2574
- # settings schema), so save_ops_db_settings writes them to
2575
- # ops.npy but leaves settings.npy / db.npy untouched. That keeps
2576
- # settings.npy as a record of suite2p stages and lets ops.npy
2577
- # carry the post-processing knobs separately.
2578
- current_ops["dff_window_size"] = dff_window_size
2579
- current_ops["dff_percentile"] = dff_percentile
2580
- current_ops["dff_smooth_window"] = dff_smooth_window
2581
- current_ops["correct_neuropil"] = bool(correct_neuropil)
2582
-
2583
2627
  _add_processing_step(
2584
2628
  current_ops,
2585
2629
  "dff_calculation",
@@ -2588,6 +2632,34 @@ def run_plane(
2588
2632
  )
2589
2633
  save_ops_db_settings(ops_file, current_ops)
2590
2634
 
2635
+ # 3b. Persist post-processing kwargs to ops.npy unconditionally.
2636
+ # These live as top-level ops keys (NOT in the suite2p settings
2637
+ # schema), so settings.npy / db.npy stay a record of the suite2p
2638
+ # stages only — ops.npy carries the lsp / GUI-tunable knobs. Done
2639
+ # outside the F.npy/Fneu.npy gate above so detection-skipped runs
2640
+ # still leave a record of which knobs the caller passed in. Callers
2641
+ # like mbo_utilities / mbo studio diff these against their dataclass
2642
+ # defaults to flag "modified" parameters in the GUI.
2643
+ if ops_file.exists():
2644
+ try:
2645
+ _post_ops = load_ops(ops_file)
2646
+ _post_ops["dff_window_size"] = dff_window_size
2647
+ _post_ops["dff_percentile"] = dff_percentile
2648
+ _post_ops["dff_smooth_window"] = dff_smooth_window
2649
+ _post_ops["correct_neuropil"] = bool(correct_neuropil)
2650
+ _post_ops["accept_all_cells"] = bool(accept_all_cells)
2651
+ _post_ops["save_json"] = bool(save_json)
2652
+ # cell_filters: list[dict] (or None). Stored as-is so a reload
2653
+ # can reconstruct each criterion's enabled/value pair.
2654
+ _post_ops["cell_filters"] = cell_filters
2655
+ # rastermap_kwargs: nested dict {"planar": {...}, "volumetric":
2656
+ # {...}} or None. Presence of a key is the per-mode enable
2657
+ # signal; sub-dict contents override Rastermap() defaults.
2658
+ _post_ops["rastermap_kwargs"] = rastermap_kwargs
2659
+ save_ops_db_settings(ops_file, _post_ops)
2660
+ except Exception as _e:
2661
+ print(f" Warning: persisting post-processing kwargs failed: {_e}")
2662
+
2591
2663
  # 3b. ROI statistics
2592
2664
  try:
2593
2665
  from lbm_suite2p_python.postprocessing import compute_roi_stats
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lbm_suite2p_python
3
- Version: 3.0.3
3
+ Version: 3.0.5
4
4
  Summary: Calcium Imaging Pipeline built with Suite2p, Cellpose and Rastermap
5
5
  License-Expression: BSD-3-Clause
6
6
  Project-URL: homepage, https://github.com/MillerBrainObservatory/LBM-Suite2p-Python
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
11
11
  Requires-Python: <3.14,>=3.12.7
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.md
14
- Requires-Dist: mbo_utilities>=3.0.2
14
+ Requires-Dist: mbo_utilities>=3.0.3
15
15
  Requires-Dist: suite2p>=1.0.0.1
16
16
  Requires-Dist: setuptools<81
17
17
  Provides-Extra: rastermap
@@ -1,4 +1,4 @@
1
- mbo_utilities>=3.0.2
1
+ mbo_utilities>=3.0.3
2
2
  suite2p>=1.0.0.1
3
3
  setuptools<81
4
4
 
@@ -1,106 +1,106 @@
1
- [build-system]
2
- requires = ["setuptools>=61", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "lbm_suite2p_python"
7
- version = "3.0.3"
8
- description = "Calcium Imaging Pipeline built with Suite2p, Cellpose and Rastermap"
9
- readme = "README.md"
10
- license = "BSD-3-Clause"
11
- requires-python = ">=3.12.7,<3.14"
12
- keywords = ["Pipeline", "Numpy", "Microscopy", "ScanImage", "Suite2p", "tiff"]
13
- urls = {homepage = "https://github.com/MillerBrainObservatory/LBM-Suite2p-Python"}
14
- classifiers=[
15
- "Development Status :: 3 - Alpha",
16
- "Intended Audience :: Science/Research",
17
- "Programming Language :: Python :: 3 :: Only",
18
- ]
19
-
20
- dependencies = [
21
- "mbo_utilities>=3.0.2",
22
- "suite2p>=1.0.0.1",
23
- "setuptools<81",
24
- ]
25
-
26
- [project.scripts]
27
- lsp = "lbm_suite2p_python.__main__:main"
28
- cellpose-gui = "lbm_suite2p_python.gui:main"
29
-
30
- [project.optional-dependencies]
31
- rastermap = [
32
- "rastermap",
33
- ]
34
- # Cellpose for anatomical cell detection (requires PyTorch)
35
- cellpose = [
36
- "cellpose>=4.0.6",
37
- ]
38
- # All optional dependencies
39
- all = [
40
- "lbm_suite2p_python[rastermap,cellpose]",
41
- ]
42
-
43
- [dependency-groups]
44
- dev = [
45
- "pytest>=8.0.0",
46
- ]
47
- docs = [
48
- "docutils>=0.21.2",
49
- "myst-nb>=1.2.0",
50
- "sphinx>=8.1.3",
51
- "roman-numerals-py>=2.0.0,<3.0.0", # 3.x is broken
52
- "sphinx-autodoc2>=0.5.0",
53
- "sphinx-copybutton>=0.5.2",
54
- "sphinx_togglebutton",
55
- "sphinx-design>=0.6.1",
56
- "sphinxcontrib-bibtex",
57
- "sphinx-tippy",
58
- "sphinx_book_theme",
59
- "numpydoc",
60
- "ipykernel",
61
- "sphinxcontrib-images",
62
- "sphinxcontrib-video",
63
- "jupytext",
64
- "scikit-image",
65
- "scipy",
66
- "pandas",
67
- "suite2p",
68
- ]
69
-
70
- # https://github.com/charliermarsh/ruff
71
- [tool.ruff]
72
- line-length = 88
73
- src = ["lbm_suite2p_python"]
74
- exclude = ["docs", "exclude", "demos", "scripts", "dev"]
75
-
76
- [tool.ruff.lint]
77
- pydocstyle = { convention = "numpy" }
78
- select = ["ALL"]
79
- ignore = [
80
- "D401", # First line should be in imperative mood (remove to opt in)
81
- "COM812", # Missing trailing comma (conflicts with ruff format)
82
- "ISC001", # Import sorting (conflicts with ruff format)
83
- "FIX002", # Fixable issue
84
- "DOC201", # TODO enable in follow-up PR; no doc for return type.
85
- "FBT", # TODO: enable in follow-up PR; require bool options to be keyword-only.
86
- ]
87
-
88
- [tool.ruff.lint.per-file-ignores]
89
- "docs/*.py" = ["D"]
90
-
91
- [tool.setuptools.exclude-package-data]
92
- "*" = ["data/*"]
93
-
94
- [tool.setuptools.packages.find]
95
- where = ["."]
96
- include = ["lbm_suite2p_python*"]
97
-
98
- [tool.coverage.report]
99
- exclude_lines = [
100
- "pragma: no cover",
101
- "if TYPE_CHECKING:",
102
- "@overload",
103
- "except ImportError",
104
- "\\.\\.\\.",
105
- "raise NotImplementedError()"
106
- ]
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "lbm_suite2p_python"
7
+ version = "3.0.5"
8
+ description = "Calcium Imaging Pipeline built with Suite2p, Cellpose and Rastermap"
9
+ readme = "README.md"
10
+ license = "BSD-3-Clause"
11
+ requires-python = ">=3.12.7,<3.14"
12
+ keywords = ["Pipeline", "Numpy", "Microscopy", "ScanImage", "Suite2p", "tiff"]
13
+ urls = {homepage = "https://github.com/MillerBrainObservatory/LBM-Suite2p-Python"}
14
+ classifiers=[
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Science/Research",
17
+ "Programming Language :: Python :: 3 :: Only",
18
+ ]
19
+
20
+ dependencies = [
21
+ "mbo_utilities>=3.0.3",
22
+ "suite2p>=1.0.0.1",
23
+ "setuptools<81",
24
+ ]
25
+
26
+ [project.scripts]
27
+ lsp = "lbm_suite2p_python.__main__:main"
28
+ cellpose-gui = "lbm_suite2p_python.gui:main"
29
+
30
+ [project.optional-dependencies]
31
+ rastermap = [
32
+ "rastermap",
33
+ ]
34
+ # Cellpose for anatomical cell detection (requires PyTorch)
35
+ cellpose = [
36
+ "cellpose>=4.0.6",
37
+ ]
38
+ # All optional dependencies
39
+ all = [
40
+ "lbm_suite2p_python[rastermap,cellpose]",
41
+ ]
42
+
43
+ [dependency-groups]
44
+ dev = [
45
+ "pytest>=8.0.0",
46
+ ]
47
+ docs = [
48
+ "docutils>=0.21.2",
49
+ "myst-nb>=1.2.0",
50
+ "sphinx>=8.1.3",
51
+ "roman-numerals-py>=2.0.0,<3.0.0", # 3.x is broken
52
+ "sphinx-autodoc2>=0.5.0",
53
+ "sphinx-copybutton>=0.5.2",
54
+ "sphinx_togglebutton",
55
+ "sphinx-design>=0.6.1",
56
+ "sphinxcontrib-bibtex",
57
+ "sphinx-tippy",
58
+ "sphinx_book_theme",
59
+ "numpydoc",
60
+ "ipykernel",
61
+ "sphinxcontrib-images",
62
+ "sphinxcontrib-video",
63
+ "jupytext",
64
+ "scikit-image",
65
+ "scipy",
66
+ "pandas",
67
+ "suite2p",
68
+ ]
69
+
70
+ # https://github.com/charliermarsh/ruff
71
+ [tool.ruff]
72
+ line-length = 88
73
+ src = ["lbm_suite2p_python"]
74
+ exclude = ["docs", "exclude", "demos", "scripts", "dev"]
75
+
76
+ [tool.ruff.lint]
77
+ pydocstyle = { convention = "numpy" }
78
+ select = ["ALL"]
79
+ ignore = [
80
+ "D401", # First line should be in imperative mood (remove to opt in)
81
+ "COM812", # Missing trailing comma (conflicts with ruff format)
82
+ "ISC001", # Import sorting (conflicts with ruff format)
83
+ "FIX002", # Fixable issue
84
+ "DOC201", # TODO enable in follow-up PR; no doc for return type.
85
+ "FBT", # TODO: enable in follow-up PR; require bool options to be keyword-only.
86
+ ]
87
+
88
+ [tool.ruff.lint.per-file-ignores]
89
+ "docs/*.py" = ["D"]
90
+
91
+ [tool.setuptools.exclude-package-data]
92
+ "*" = ["data/*"]
93
+
94
+ [tool.setuptools.packages.find]
95
+ where = ["."]
96
+ include = ["lbm_suite2p_python*"]
97
+
98
+ [tool.coverage.report]
99
+ exclude_lines = [
100
+ "pragma: no cover",
101
+ "if TYPE_CHECKING:",
102
+ "@overload",
103
+ "except ImportError",
104
+ "\\.\\.\\.",
105
+ "raise NotImplementedError()"
106
+ ]