lbm_suite2p_python 3.2.1__tar.gz → 3.2.2__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.2.1/lbm_suite2p_python.egg-info → lbm_suite2p_python-3.2.2}/PKG-INFO +4 -2
  2. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/cli.py +132 -17
  3. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2/lbm_suite2p_python.egg-info}/PKG-INFO +4 -2
  4. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python.egg-info/requires.txt +3 -1
  5. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/pyproject.toml +117 -106
  6. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/LICENSE.md +0 -0
  7. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/MANIFEST.in +0 -0
  8. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/README.md +0 -0
  9. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/__init__.py +0 -0
  10. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/__main__.py +0 -0
  11. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/_benchmarking.py +0 -0
  12. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/cellpose.py +0 -0
  13. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/conversion.py +0 -0
  14. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/db_settings.py +0 -0
  15. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/default_ops.py +0 -0
  16. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/grid_search.py +0 -0
  17. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/gui.py +0 -0
  18. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/merging.py +0 -0
  19. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/postprocessing.py +0 -0
  20. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/run_lsp.py +0 -0
  21. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/utils.py +0 -0
  22. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/volume.py +0 -0
  23. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python/zplane.py +0 -0
  24. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python.egg-info/SOURCES.txt +0 -0
  25. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python.egg-info/dependency_links.txt +0 -0
  26. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python.egg-info/entry_points.txt +0 -0
  27. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/lbm_suite2p_python.egg-info/top_level.txt +0 -0
  28. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/setup.cfg +0 -0
  29. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/tests/test_frame_count_aliases.py +0 -0
  30. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/tests/test_pipeline_parameters.py +0 -0
  31. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/tests/test_refactored_pipeline.py +0 -0
  32. {lbm_suite2p_python-3.2.1 → lbm_suite2p_python-3.2.2}/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.2.1
3
+ Version: 3.2.2
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,9 +11,11 @@ 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.2.1
14
+ Requires-Dist: mbo_utilities>=3.2.7
15
15
  Requires-Dist: suite2p>=1.0.0.1
16
16
  Requires-Dist: setuptools<81
17
+ Requires-Dist: torch
18
+ Requires-Dist: torchvision
17
19
  Provides-Extra: rastermap
18
20
  Requires-Dist: rastermap; extra == "rastermap"
19
21
  Provides-Extra: cellpose
@@ -23,6 +23,7 @@ Examples:
23
23
  """
24
24
 
25
25
  import argparse
26
+ import json
26
27
  import sys
27
28
  from pathlib import Path
28
29
  from typing import Any
@@ -67,6 +68,7 @@ def _get_ops_help() -> dict[str, str]:
67
68
  "cellprob_threshold": "cellpose cell probability threshold (lower = more cells)",
68
69
  "flow_threshold": "cellpose flow error threshold",
69
70
  "anatomical_only": "cellpose detection mode: 0=off, 1=max_proj, 2=mean, 3=enhanced, 4=max",
71
+ "algorithm": "detection algorithm: sparsery, sourcery, or cellpose",
70
72
  "pretrained_model": "cellpose model name (e.g., cpsam, cyto2, nuclei)",
71
73
  "do_registration": "whether to run motion correction",
72
74
  "nonrigid": "use nonrigid (piecewise) registration",
@@ -103,6 +105,10 @@ Examples:
103
105
  lsp data/ output/ --planes 1 2 3 # specific planes (1-indexed)
104
106
  lsp data/ output/ --num-timepoints 500 # quick test with 500 frames
105
107
  lsp data/ output/ --diameter 8 # custom cell diameter
108
+ lsp data/ output/ --tau 1.3 --algorithm cellpose # decay + detection algorithm
109
+ lsp data/ output/ --fix-phase --phasecorr-method median # reader phase correction
110
+ lsp data/ output/ --reader-kwargs '{"roi": 2}' # arbitrary imread kwargs
111
+ lsp data/ output/ --ops-file my_ops.json # load saved ops (CLI flags override)
106
112
  lsp --list-ops # show all suite2p parameters
107
113
  """,
108
114
  )
@@ -245,15 +251,57 @@ Examples:
245
251
  help="maximum cell diameter in pixels"
246
252
  )
247
253
 
248
- # reader options (for raw data)
254
+ # reader options (forwarded to mbo_utilities.imread)
249
255
  reader = parser.add_argument_group("reader options (raw scanimage data)")
250
256
  reader.add_argument(
251
- "--fix-phase", action="store_true",
252
- help="apply bidirectional phase correction"
257
+ "--fix-phase", action=argparse.BooleanOptionalAction, default=None,
258
+ help="bidirectional phase correction (reader default: on)"
253
259
  )
254
260
  reader.add_argument(
255
- "--use-fft", action="store_true",
256
- help="use FFT for subpixel phase correction"
261
+ "--use-fft", action=argparse.BooleanOptionalAction, default=None,
262
+ help="FFT-based subpixel phase correction"
263
+ )
264
+ reader.add_argument(
265
+ "--phasecorr-method", choices=["mean", "median", "max"], default=None,
266
+ help="phase-correction reduction method (default: mean)"
267
+ )
268
+ reader.add_argument(
269
+ "--channel", type=int, default=None,
270
+ help="zero-based color channel to read (multi-channel sources)"
271
+ )
272
+ reader.add_argument(
273
+ "--reader-kwargs", type=str, default=None, metavar="JSON",
274
+ help='extra imread kwargs as JSON, e.g. \'{"roi": 2}\''
275
+ )
276
+
277
+ # writer options (forwarded to the binary/zarr writer)
278
+ writer = parser.add_argument_group("writer options")
279
+ writer.add_argument(
280
+ "--writer-kwargs", type=str, default=None, metavar="JSON",
281
+ help='extra writer kwargs as JSON, e.g. \'{"target_chunk_mb": 200}\''
282
+ )
283
+
284
+ # rastermap options
285
+ rmap = parser.add_argument_group("rastermap options")
286
+ rmap.add_argument(
287
+ "--rastermap", action="store_true",
288
+ help="enable rastermap (planar + volumetric) with default settings"
289
+ )
290
+ rmap.add_argument(
291
+ "--rastermap-kwargs", type=str, default=None, metavar="JSON",
292
+ help='rastermap config JSON with "planar"/"volumetric" keys, '
293
+ 'e.g. \'{"planar": {"n_clusters": 50}}\''
294
+ )
295
+
296
+ # advanced
297
+ advanced = parser.add_argument_group("advanced")
298
+ advanced.add_argument(
299
+ "--ops-file", type=str, default=None,
300
+ help="base ops from a .npy/.json file or suite2p dir; CLI flags override"
301
+ )
302
+ advanced.add_argument(
303
+ "--replot", action=argparse.BooleanOptionalAction, default=True,
304
+ help="regenerate per-plane figures (default: on)"
257
305
  )
258
306
 
259
307
  # dynamically add all ops parameters
@@ -324,8 +372,9 @@ def list_ops():
324
372
  "Main Settings": ["nplanes", "nchannels", "fs", "tau", "frames_include"],
325
373
  "Registration": ["do_registration", "nonrigid", "batch_size", "maxregshift",
326
374
  "smooth_sigma", "nimg_init", "subpixel"],
327
- "Cell Detection": ["roidetect", "sparse_mode", "spatial_scale", "threshold_scaling",
328
- "max_overlap", "connected", "nbinned", "max_iterations"],
375
+ "Cell Detection": ["roidetect", "algorithm", "sparse_mode", "spatial_scale",
376
+ "threshold_scaling", "max_overlap", "connected", "nbinned",
377
+ "max_iterations"],
329
378
  "Cellpose": ["anatomical_only", "diameter", "cellprob_threshold", "flow_threshold",
330
379
  "pretrained_model", "spatial_hp_cp"],
331
380
  "Signal Extraction": ["neuropil_extract", "neucoeff", "spikedetect",
@@ -405,6 +454,65 @@ def build_cell_filters(args) -> list | None:
405
454
  return filters if filters else None
406
455
 
407
456
 
457
+ def _parse_json_arg(flag: str, value: str) -> dict:
458
+ """parse a JSON object from a CLI flag value; exit cleanly on error."""
459
+ try:
460
+ parsed = json.loads(value)
461
+ except json.JSONDecodeError as e:
462
+ raise SystemExit(f"Error: {flag} is not valid JSON: {e}")
463
+ if not isinstance(parsed, dict):
464
+ raise SystemExit(f"Error: {flag} must be a JSON object")
465
+ return parsed
466
+
467
+
468
+ def _load_ops_file(path: str) -> dict:
469
+ """load a base ops dict from a .json/.npy file or a suite2p directory."""
470
+ from lbm_suite2p_python import load_ops
471
+
472
+ p = Path(path).expanduser()
473
+ if p.suffix.lower() == ".json":
474
+ if not p.exists():
475
+ raise SystemExit(f"Error: --ops-file not found: {p}")
476
+ with open(p, "r", encoding="utf-8") as fh:
477
+ data = json.load(fh)
478
+ if not isinstance(data, dict):
479
+ raise SystemExit("Error: --ops-file JSON must be an object")
480
+ return data
481
+ return load_ops(p)
482
+
483
+
484
+ def build_reader_kwargs(args) -> dict | None:
485
+ """build imread kwargs from CLI reader args (None if empty)."""
486
+ kw = {}
487
+ if args.fix_phase is not None:
488
+ kw["fix_phase"] = args.fix_phase
489
+ if args.use_fft is not None:
490
+ kw["use_fft"] = args.use_fft
491
+ if args.phasecorr_method is not None:
492
+ kw["phasecorr_method"] = args.phasecorr_method
493
+ if args.channel is not None:
494
+ kw["channel"] = args.channel
495
+ if args.reader_kwargs:
496
+ kw.update(_parse_json_arg("--reader-kwargs", args.reader_kwargs))
497
+ return kw or None
498
+
499
+
500
+ def build_writer_kwargs(args) -> dict | None:
501
+ """build writer kwargs from CLI writer args (None if empty)."""
502
+ if args.writer_kwargs:
503
+ return _parse_json_arg("--writer-kwargs", args.writer_kwargs)
504
+ return None
505
+
506
+
507
+ def build_rastermap_kwargs(args) -> dict | None:
508
+ """build rastermap_kwargs from CLI args (None if disabled)."""
509
+ if args.rastermap_kwargs:
510
+ return _parse_json_arg("--rastermap-kwargs", args.rastermap_kwargs)
511
+ if args.rastermap:
512
+ return {"planar": {}, "volumetric": {}}
513
+ return None
514
+
515
+
408
516
  def build_ops(args, base_ops: dict) -> dict:
409
517
  """build ops dict from CLI args, overriding base_ops."""
410
518
  from lbm_suite2p_python.default_ops import s2p_ops
@@ -512,6 +620,13 @@ def main():
512
620
 
513
621
  output_path.mkdir(parents=True, exist_ok=True)
514
622
 
623
+ # parse config/advanced args up front so invalid JSON or a missing ops
624
+ # file fails before any logging or processing work begins
625
+ base_extra_ops = _load_ops_file(args.ops_file) if args.ops_file else None
626
+ reader_kwargs = build_reader_kwargs(args)
627
+ writer_kwargs = build_writer_kwargs(args)
628
+ rastermap_kwargs = build_rastermap_kwargs(args)
629
+
515
630
  log_path = output_path / "log.txt"
516
631
  log_file = open(log_path, "w", encoding="utf-8", buffering=1)
517
632
  _orig_stdout, _orig_stderr = sys.stdout, sys.stderr
@@ -538,17 +653,10 @@ def main():
538
653
  print(f"Input: {input_path}")
539
654
  print(f"Output: {output_path}")
540
655
 
541
- # build ops
542
- base_ops = lsp.default_ops()
656
+ # build ops (optionally starting from a user-supplied ops file)
657
+ base_ops = lsp.default_ops(ops=base_extra_ops) if base_extra_ops else lsp.default_ops()
543
658
  ops = build_ops(args, base_ops)
544
659
 
545
- # build reader kwargs
546
- reader_kwargs = {}
547
- if args.fix_phase:
548
- reader_kwargs["fix_phase"] = True
549
- if args.use_fft:
550
- reader_kwargs["use_fft"] = True
551
-
552
660
  # build cell filters
553
661
  cell_filters = build_cell_filters(args)
554
662
 
@@ -562,6 +670,10 @@ def main():
562
670
  print(f" Cellpose model: {ops.get('pretrained_model', 'cpsam')}")
563
671
  if cell_filters:
564
672
  print(f" Cell filters: {cell_filters}")
673
+ if reader_kwargs:
674
+ print(f" Reader: {reader_kwargs}")
675
+ if rastermap_kwargs:
676
+ print(f" Rastermap: {sorted(rastermap_kwargs)}")
565
677
 
566
678
  print(f"\n{'='*60}\n")
567
679
 
@@ -590,7 +702,10 @@ def main():
590
702
  cell_filters=cell_filters,
591
703
  accept_all_cells=args.accept_all_cells,
592
704
  save_json=args.save_json,
593
- reader_kwargs=reader_kwargs if reader_kwargs else None,
705
+ reader_kwargs=reader_kwargs,
706
+ writer_kwargs=writer_kwargs,
707
+ rastermap_kwargs=rastermap_kwargs,
708
+ replot=args.replot,
594
709
  workers=args.workers,
595
710
  skip_volumetric=args.skip_volumetric,
596
711
  threads_per_worker=args.threads_per_worker,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lbm_suite2p_python
3
- Version: 3.2.1
3
+ Version: 3.2.2
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,9 +11,11 @@ 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.2.1
14
+ Requires-Dist: mbo_utilities>=3.2.7
15
15
  Requires-Dist: suite2p>=1.0.0.1
16
16
  Requires-Dist: setuptools<81
17
+ Requires-Dist: torch
18
+ Requires-Dist: torchvision
17
19
  Provides-Extra: rastermap
18
20
  Requires-Dist: rastermap; extra == "rastermap"
19
21
  Provides-Extra: cellpose
@@ -1,6 +1,8 @@
1
- mbo_utilities>=3.2.1
1
+ mbo_utilities>=3.2.7
2
2
  suite2p>=1.0.0.1
3
3
  setuptools<81
4
+ torch
5
+ torchvision
4
6
 
5
7
  [all]
6
8
  lbm_suite2p_python[cellpose,rastermap]
@@ -1,106 +1,117 @@
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.2.1"
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.2.1",
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.2.2"
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.2.7",
22
+ "suite2p>=1.0.0.1",
23
+ "setuptools<81",
24
+ "torch",
25
+ "torchvision",
26
+ ]
27
+
28
+ [project.scripts]
29
+ lsp = "lbm_suite2p_python.__main__:main"
30
+ cellpose-gui = "lbm_suite2p_python.gui:main"
31
+
32
+ [project.optional-dependencies]
33
+ rastermap = [
34
+ "rastermap",
35
+ ]
36
+ # Cellpose for anatomical cell detection (requires PyTorch)
37
+ cellpose = [
38
+ "cellpose>=4.0.6",
39
+ ]
40
+ # All optional dependencies
41
+ all = [
42
+ "lbm_suite2p_python[rastermap,cellpose]",
43
+ ]
44
+
45
+ [dependency-groups]
46
+ dev = [
47
+ "pytest>=8.0.0",
48
+ ]
49
+ docs = [
50
+ "docutils>=0.21.2",
51
+ "myst-nb>=1.2.0",
52
+ "sphinx>=8.1.3",
53
+ "roman-numerals-py>=2.0.0,<3.0.0", # 3.x is broken
54
+ "sphinx-autodoc2>=0.5.0",
55
+ "sphinx-copybutton>=0.5.2",
56
+ "sphinx_togglebutton",
57
+ "sphinx-design>=0.6.1",
58
+ "sphinxcontrib-bibtex",
59
+ "sphinx-tippy",
60
+ "sphinx_book_theme",
61
+ "numpydoc",
62
+ "ipykernel",
63
+ "sphinxcontrib-images",
64
+ "sphinxcontrib-video",
65
+ "jupytext",
66
+ "scikit-image",
67
+ "scipy",
68
+ "pandas",
69
+ "suite2p",
70
+ ]
71
+
72
+ [tool.uv.sources]
73
+ torch = [{ index = "pytorch-cu126" }]
74
+ torchvision = [{ index = "pytorch-cu126" }]
75
+
76
+ [[tool.uv.index]]
77
+ name = "pytorch-cu126"
78
+ url = "https://download.pytorch.org/whl/cu126"
79
+ explicit = true
80
+
81
+ # https://github.com/charliermarsh/ruff
82
+ [tool.ruff]
83
+ line-length = 88
84
+ src = ["lbm_suite2p_python"]
85
+ exclude = ["docs", "exclude", "demos", "scripts", "dev"]
86
+
87
+ [tool.ruff.lint]
88
+ pydocstyle = { convention = "numpy" }
89
+ select = ["ALL"]
90
+ ignore = [
91
+ "D401", # First line should be in imperative mood (remove to opt in)
92
+ "COM812", # Missing trailing comma (conflicts with ruff format)
93
+ "ISC001", # Import sorting (conflicts with ruff format)
94
+ "FIX002", # Fixable issue
95
+ "DOC201", # TODO enable in follow-up PR; no doc for return type.
96
+ "FBT", # TODO: enable in follow-up PR; require bool options to be keyword-only.
97
+ ]
98
+
99
+ [tool.ruff.lint.per-file-ignores]
100
+ "docs/*.py" = ["D"]
101
+
102
+ [tool.setuptools.exclude-package-data]
103
+ "*" = ["data/*"]
104
+
105
+ [tool.setuptools.packages.find]
106
+ where = ["."]
107
+ include = ["lbm_suite2p_python*"]
108
+
109
+ [tool.coverage.report]
110
+ exclude_lines = [
111
+ "pragma: no cover",
112
+ "if TYPE_CHECKING:",
113
+ "@overload",
114
+ "except ImportError",
115
+ "\\.\\.\\.",
116
+ "raise NotImplementedError()"
117
+ ]