lbm_suite2p_python 2.0.3__tar.gz → 2.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 (24) hide show
  1. {lbm_suite2p_python-2.0.3/lbm_suite2p_python.egg-info → lbm_suite2p_python-2.0.5}/PKG-INFO +1 -11
  2. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/run_lsp.py +138 -95
  3. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5/lbm_suite2p_python.egg-info}/PKG-INFO +1 -11
  4. lbm_suite2p_python-2.0.5/lbm_suite2p_python.egg-info/requires.txt +1 -0
  5. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/pyproject.toml +15 -46
  6. lbm_suite2p_python-2.0.3/lbm_suite2p_python.egg-info/requires.txt +0 -14
  7. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/LICENSE.md +0 -0
  8. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/MANIFEST.in +0 -0
  9. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/README.md +0 -0
  10. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/__init__.py +0 -0
  11. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/__main__.py +0 -0
  12. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/_benchmarking.py +0 -0
  13. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/default_ops.py +0 -0
  14. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/merging.py +0 -0
  15. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/postprocessing.py +0 -0
  16. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/utils.py +0 -0
  17. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/volume.py +0 -0
  18. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python/zplane.py +0 -0
  19. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python.egg-info/SOURCES.txt +0 -0
  20. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python.egg-info/dependency_links.txt +0 -0
  21. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python.egg-info/entry_points.txt +0 -0
  22. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/lbm_suite2p_python.egg-info/top_level.txt +0 -0
  23. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.0.5}/setup.cfg +0 -0
  24. {lbm_suite2p_python-2.0.3 → lbm_suite2p_python-2.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: 2.0.3
3
+ Version: 2.0.5
4
4
  Summary: Light Beads Microscopy Pipeline using Suite2p
5
5
  License-Expression: BSD-3-Clause
6
6
  Project-URL: homepage, https://github.com/MillerBrainObservatory/LBM-Suite2p-Python
@@ -12,16 +12,6 @@ Requires-Python: <3.12.10,>=3.12.7
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.md
14
14
  Requires-Dist: mbo_utilities>=2.0.4
15
- Provides-Extra: cpsam
16
- Requires-Dist: cellpose==4.0.6; extra == "cpsam"
17
- Requires-Dist: pytorch; extra == "cpsam"
18
- Requires-Dist: torchaudio; extra == "cpsam"
19
- Provides-Extra: cpu
20
- Requires-Dist: torch>=2.7.0; extra == "cpu"
21
- Requires-Dist: torchvision>=0.22.0; extra == "cpu"
22
- Provides-Extra: cu126
23
- Requires-Dist: torch>=2.7.0; extra == "cu126"
24
- Requires-Dist: torchvision>=0.22.0; extra == "cu126"
25
15
  Dynamic: license-file
26
16
 
27
17
  # Light Beads Microscopy (LBM) Pipeline: Suite2p
@@ -18,10 +18,7 @@ from lbm_suite2p_python.postprocessing import (
18
18
  )
19
19
  from mbo_utilities.log import get as get_logger
20
20
 
21
- from lbm_suite2p_python.zplane import (
22
- save_pc_panels_and_metrics,
23
- plot_zplane_figures
24
- )
21
+ from lbm_suite2p_python.zplane import save_pc_panels_and_metrics, plot_zplane_figures
25
22
 
26
23
  logger = get_logger("run_lsp")
27
24
 
@@ -31,7 +28,9 @@ from lbm_suite2p_python.volume import (
31
28
  plot_volume_neuron_counts,
32
29
  get_volume_stats,
33
30
  )
34
- from mbo_utilities.file_io import get_plane_from_filename # derive_tag_from_filename, PIPELINE_TAGS
31
+ from mbo_utilities.file_io import (
32
+ get_plane_from_filename,
33
+ ) # derive_tag_from_filename, PIPELINE_TAGS
35
34
 
36
35
  PIPELINE_TAGS = ("plane", "roi", "z", "plane_", "roi_", "z_")
37
36
 
@@ -160,6 +159,7 @@ def run_volume(
160
159
  - Optional rastermap clustering results
161
160
  """
162
161
  from mbo_utilities.file_io import get_files, get_plane_from_filename
162
+
163
163
  start = time.time()
164
164
  if save_path is None:
165
165
  save_path = Path(input_files[0]).parent
@@ -204,6 +204,7 @@ def run_volume(
204
204
  if "roi" in Path(input_files[0]).stem.lower():
205
205
  print("Detected mROI data, merging ROIs for each z-plane...")
206
206
  from .merging import merge_mrois
207
+
207
208
  merged_savepath = save_path.joinpath("merged_mrois")
208
209
  merge_mrois(save_path, merged_savepath)
209
210
  save_path = merged_savepath
@@ -269,57 +270,54 @@ def run_volume(
269
270
  return all_ops
270
271
 
271
272
 
272
- def _should_write_bin(ops_path: Path, force: bool = False) -> bool:
273
- """
274
- Decide whether raw binary export should be performed before registration.
275
-
276
- Conditions that trigger re-write:
277
- - force=True
278
- - bin file missing (data.bin or data_chan2.bin)
279
- - ops.npy missing
280
- - mismatch between ops metadata (Ly, Lx, nframes) and bin file size
281
- - bin file unreadable or truncated
282
- """
273
+ def _should_write_bin(ops_path: Path, force: bool = False, *, validate_chan2: bool | None = None, expected_dtype: np.dtype = np.int16) -> bool:
283
274
  if force:
284
275
  return True
285
276
  ops_path = Path(ops_path)
286
277
  if not ops_path.is_file():
287
278
  return True
288
-
289
- ops = np.load(ops_path, allow_pickle=True).item()
290
-
291
- # Check both functional and optional structural binaries
292
- bin_candidates = []
293
- if "raw_file" in ops:
294
- bin_candidates.append(Path(ops["raw_file"]))
295
- if "chan2_file" in ops:
296
- bin_candidates.append(Path(ops["chan2_file"]))
297
-
298
- for bin_path in bin_candidates:
299
- if not bin_path.is_file():
279
+ raw_path = ops_path.parent / "data_raw.bin"
280
+ chan2_path = ops_path.parent / "data_chan2.bin"
281
+ if not raw_path.is_file():
282
+ return True
283
+ try:
284
+ ops = np.load(ops_path, allow_pickle=True).item()
285
+ if validate_chan2 is None:
286
+ validate_chan2 = (ops.get("align_by_chan", 1) == 2)
287
+ Ly = ops.get("Ly")
288
+ Lx = ops.get("Lx")
289
+ nframes_raw = ops.get("nframes_chan1") or ops.get("nframes") or ops.get("num_frames")
290
+ if (not raw_path.is_file()) or (None in (nframes_raw, Ly, Lx)) or (nframes_raw <= 0 or Ly <= 0 or Lx <= 0):
291
+ return True
292
+ expected_size_raw = int(nframes_raw) * int(Ly) * int(Lx) * np.dtype(expected_dtype).itemsize
293
+ actual_size_raw = raw_path.stat().st_size
294
+ if actual_size_raw != expected_size_raw or actual_size_raw == 0:
300
295
  return True
301
296
  try:
302
- Ly, Lx = ops.get("Ly"), ops.get("Lx")
303
- nframes = (
304
- ops.get("nframes_chan2")
305
- if "chan2" in bin_path.name
306
- else ops.get("nframes_chan1", ops.get("nframes"))
307
- )
308
- if None in (Ly, Lx, nframes):
309
- return True
310
-
311
- expected_size = nframes * Ly * Lx * np.dtype(np.int16).itemsize
312
- actual_size = bin_path.stat().st_size
313
- if actual_size != expected_size:
314
- return True
315
-
316
- arr = np.memmap(bin_path, dtype=np.int16, mode="r", shape=(nframes, Ly, Lx))
297
+ arr = np.memmap(raw_path, dtype=expected_dtype, mode="r", shape=(int(nframes_raw), int(Ly), int(Lx)))
317
298
  _ = arr[0, 0, 0]
318
299
  del arr
319
- except Exception as e:
320
- print(f"Bin validation failed for {bin_path}: {e}")
300
+ except Exception:
321
301
  return True
322
- return False # all checks passed
302
+ if validate_chan2:
303
+ nframes_chan2 = ops.get("nframes_chan2")
304
+ if (not chan2_path.is_file()) or (nframes_chan2 is None) or (nframes_chan2 <= 0):
305
+ return True
306
+ expected_size_chan2 = int(nframes_chan2) * int(Ly) * int(Lx) * np.dtype(expected_dtype).itemsize
307
+ actual_size_chan2 = chan2_path.stat().st_size
308
+ if actual_size_chan2 != expected_size_chan2 or actual_size_chan2 == 0:
309
+ return True
310
+ try:
311
+ arr2 = np.memmap(chan2_path, dtype=expected_dtype, mode="r", shape=(int(nframes_chan2), int(Ly), int(Lx)))
312
+ _ = arr2[0, 0, 0]
313
+ del arr2
314
+ except Exception:
315
+ return True
316
+ return False
317
+ except Exception as e:
318
+ print(f"Bin validation failed for {ops_path.parent}: {e}")
319
+ return True
320
+
323
321
 
324
322
  def _should_register(ops_path: str | Path) -> bool:
325
323
  """
@@ -336,9 +334,8 @@ def _should_register(ops_path: str | Path) -> bool:
336
334
 
337
335
  has_ref = isinstance(ops.get("refImg"), np.ndarray)
338
336
  has_mean = isinstance(ops.get("meanImg"), np.ndarray)
339
- has_offsets = (
340
- ("xoff" in ops and np.any(np.isfinite(ops["xoff"]))) or
341
- ("yoff" in ops and np.any(np.isfinite(ops["yoff"])))
337
+ has_offsets = ("xoff" in ops and np.any(np.isfinite(ops["xoff"]))) or (
338
+ "yoff" in ops and np.any(np.isfinite(ops["yoff"]))
342
339
  )
343
340
  has_metrics = any(k in ops for k in ("regDX", "regPC", "regPC1", "regDX1"))
344
341
 
@@ -348,55 +345,73 @@ def _should_register(ops_path: str | Path) -> bool:
348
345
 
349
346
 
350
347
  def run_plane_bin(ops) -> bool:
351
- from mbo_utilities._binary import BinaryFile
352
- from suite2p.run_s2p import pipeline
353
348
  from contextlib import nullcontext
349
+ from suite2p.io.binary import BinaryFile
350
+ from suite2p.run_s2p import pipeline
354
351
 
355
352
  ops = load_ops(ops)
356
- Ly, Lx = ops["Ly"], ops["Lx"]
353
+ Ly, Lx = int(ops["Ly"]), int(ops["Lx"])
357
354
 
358
- # input functional channel (unregistered)
359
355
  raw_file = ops.get("raw_file")
360
- nframes_chan1 = ops.get("nframes_chan1") or ops.get("nframes") or ops.get("n_frames")
361
- if raw_file is None or nframes_chan1 is None:
356
+ n_func = ops.get("nframes_chan1") or ops.get("nframes") or ops.get("n_frames")
357
+ if raw_file is None or n_func is None:
362
358
  raise KeyError("Missing raw_file or nframes_chan1")
359
+ n_func = int(n_func)
363
360
 
364
- # optional structural channel
365
- chan2_file = ops.get("chan2_file", "")
366
- nframes_chan2 = ops.get("nframes_chan2", 0)
367
-
368
- ops_parent = Path(ops.get("ops_path")).parent
361
+ ops_parent = Path(ops["ops_path"]).parent
369
362
  ops["save_path"] = ops_parent
370
363
 
371
- align_structural = ops.get("align_by_chan", 1) == 2
372
- ops["align_structural"] = align_structural
373
-
374
364
  reg_file = ops_parent / "data.bin"
375
365
  ops["reg_file"] = str(reg_file)
376
366
 
377
- # sanity fix for diameter
367
+ chan2_file = ops.get("chan2_file", "")
368
+ use_chan2 = bool(chan2_file) and Path(chan2_file).exists()
369
+ n_chan2 = int(ops.get("nframes_chan2", 0)) if use_chan2 else 0
370
+
371
+ n_align = n_func if not use_chan2 else min(n_func, n_chan2)
372
+ if n_align <= 0:
373
+ raise ValueError("Non-positive frame count after alignment selection.")
374
+ if use_chan2 and (n_func != n_chan2):
375
+ print(f"[run_plane_bin] Trimming to {n_align} frames (func={n_func}, chan2={n_chan2}).")
376
+
377
+ ops["functional_chan"] = 1
378
+ ops["align_by_chan"] = 2 if use_chan2 else 1
379
+ ops["nchannels"] = 2 if use_chan2 else 1
380
+ ops["nframes"] = n_align
381
+ ops["nframes_chan1"] = n_align
382
+ if use_chan2:
383
+ ops["nframes_chan2"] = n_align
384
+
378
385
  if "diameter" in ops:
379
386
  if ops["diameter"] is not None and np.isnan(ops["diameter"]):
380
387
  ops["diameter"] = 8
381
- if (ops["diameter"] is None or ops["diameter"] == 0) and ops.get("anatomical_only", 0) > 0:
388
+ if (ops["diameter"] in (None, 0)) and ops.get("anatomical_only", 0) > 0:
382
389
  ops["diameter"] = 8
383
390
  print("Warning: diameter was not set, defaulting to 8.")
384
391
 
392
+ reg_file_chan2 = ops_parent / "data_chan2_reg.bin" if use_chan2 else None
393
+
394
+ ops["anatomical_red"] = False
395
+ ops["chan2_thres"] = 0.1
396
+
385
397
  with (
386
- BinaryFile(Ly=Ly, Lx=Lx, filename=str(reg_file), n_frames=nframes_chan1) as f_reg,
387
- BinaryFile(Ly=Ly, Lx=Lx, filename=raw_file, n_frames=nframes_chan1) as f_raw,
388
- (BinaryFile(Ly=Ly, Lx=Lx, filename=chan2_file, n_frames=nframes_chan2)
389
- if align_structural else nullcontext()) as f_reg_chan2
398
+ BinaryFile(Ly=Ly, Lx=Lx, filename=str(reg_file), n_frames=n_align) as f_reg,
399
+ BinaryFile(Ly=Ly, Lx=Lx, filename=str(raw_file), n_frames=n_align) as f_raw,
400
+ (BinaryFile(Ly=Ly, Lx=Lx, filename=str(reg_file_chan2), n_frames=n_align) if use_chan2 else nullcontext()) as f_reg_chan2,
401
+ (BinaryFile(Ly=Ly, Lx=Lx, filename=str(chan2_file), n_frames=n_align) if use_chan2 else nullcontext()) as f_raw_chan2,
390
402
  ):
391
403
  ops = pipeline(
392
404
  f_reg=f_reg,
393
405
  f_raw=f_raw,
394
- f_reg_chan2=f_reg_chan2,
395
- f_raw_chan2=f_reg_chan2 if align_structural else None,
396
- run_registration=ops.get("do_registration", True),
406
+ f_reg_chan2=f_reg_chan2 if use_chan2 else None,
407
+ f_raw_chan2=f_raw_chan2 if use_chan2 else None,
408
+ run_registration=bool(ops.get("do_registration", True)),
397
409
  ops=ops,
398
410
  stat=None,
399
411
  )
412
+
413
+ if use_chan2:
414
+ ops["reg_file_chan2"] = str(reg_file_chan2)
400
415
  np.save(ops["ops_path"], ops)
401
416
  return True
402
417
 
@@ -405,6 +420,7 @@ def run_plane(
405
420
  input_path: str | Path,
406
421
  save_path: str | Path | None = None,
407
422
  ops: dict | str | Path = None,
423
+ chan2_file: str | Path | None = None,
408
424
  keep_raw: bool = False,
409
425
  keep_reg: bool = True,
410
426
  force_reg: bool = False,
@@ -426,6 +442,8 @@ def run_plane(
426
442
  Directory to save the results.
427
443
  ops : dict, str or Path, optional
428
444
  Path to or dict of user‐supplied ops.npy. If given, it overrides any existing or generated ops.
445
+ chan2_file : str, optional
446
+ Path to structural / anatomical data used for registration.
429
447
  keep_raw : bool, default false
430
448
  if true, do not delete the raw binary (`data_raw.bin`) after processing.
431
449
  keep_reg : bool, default false
@@ -484,18 +502,15 @@ def run_plane(
484
502
  logger.setLevel(logging.DEBUG)
485
503
  logger.info("Debug mode enabled.")
486
504
 
487
- assert isinstance(input_path, (Path, str)), (
488
- f"input_path should be a pathlib.Path or string, not: {type(input_path)}"
489
- )
505
+ assert isinstance(
506
+ input_path, (Path, str)
507
+ ), f"input_path should be a pathlib.Path or string, not: {type(input_path)}"
490
508
  input_path = Path(input_path)
491
- if not input_path.is_file():
492
- if input_path.suffix != ".zarr":
493
- raise ValueError(f"Input file does not exist: {input_path}")
494
509
  input_parent = input_path.parent
495
510
 
496
- assert isinstance(save_path, (Path, str, type(None))), (
497
- f"save_path should be a pathlib.Path or string, not: {type(save_path)}"
498
- )
511
+ assert isinstance(
512
+ save_path, (Path, str, type(None))
513
+ ), f"save_path should be a pathlib.Path or string, not: {type(save_path)}"
499
514
  if save_path is None:
500
515
  logger.debug(f"save_path is None, using parent of input file: {input_parent}")
501
516
  save_path = input_parent
@@ -512,8 +527,11 @@ def run_plane(
512
527
  ops = {**ops_default, **ops_user, "data_path": str(input_path.resolve())}
513
528
 
514
529
  # suite2p diameter handling
515
- if isinstance(ops["diameter"], list) and len(
516
- ops["diameter"]) > 1 and ops["aspect"] == 1.0:
530
+ if (
531
+ isinstance(ops["diameter"], list)
532
+ and len(ops["diameter"]) > 1
533
+ and ops["aspect"] == 1.0
534
+ ):
517
535
  ops["aspect"] = ops["diameter"][0] / ops["diameter"][1] # noqa
518
536
 
519
537
  file = imread(input_path)
@@ -562,7 +580,8 @@ def run_plane(
562
580
  else:
563
581
  print(
564
582
  f"ops['roidetect'] is True with no stat.npy file present, "
565
- f"proceeding with segmentation/detection for plane {plane}.")
583
+ f"proceeding with segmentation/detection for plane {plane}."
584
+ )
566
585
  needs_detect = True
567
586
  elif (plane_dir / "stat.npy").is_file():
568
587
  # check contents of stat.npy
@@ -576,7 +595,7 @@ def run_plane(
576
595
 
577
596
  ops_file = plane_dir / "ops.npy"
578
597
 
579
- if _should_write_bin(ops_file, force=kwargs.get("force_save", False)):
598
+ if _should_write_bin(ops_file, force=force_reg):
580
599
  md_combined = {**metadata, **ops}
581
600
  imwrite(file, plane_dir, ext=".bin", metadata=md_combined, register_z=False)
582
601
  else:
@@ -609,6 +628,23 @@ def run_plane(
609
628
  "reg_file": str((plane_dir / "data.bin").resolve()),
610
629
  }
611
630
 
631
+ # optional structural (channel 2) input
632
+ if chan2_file is not None:
633
+ chan2_file = Path(chan2_file)
634
+ if not chan2_file.exists():
635
+ raise FileNotFoundError(f"chan2_path not found: {chan2_file}")
636
+
637
+ chan2_data = imread(chan2_file)
638
+ chan2_md = chan2_data.metadata if hasattr(chan2_data, "metadata") else {}
639
+ chan2_frames = chan2_md.get("num_frames") or chan2_md.get("nframes") or chan2_data.shape[0]
640
+
641
+ # write channel 2 binary automatically
642
+ imwrite(chan2_data, plane_dir, ext=".bin", metadata=chan2_md, register_z=False, structural=True)
643
+ ops["chan2_file"] = str((plane_dir / "data_chan2.bin").resolve())
644
+ ops["nframes_chan2"] = int(chan2_frames)
645
+ ops["nchannels"] = 2
646
+ ops["align_by_chan"] = 2
647
+
612
648
  if "nframes" not in ops:
613
649
  if "metadata" in ops and "shape" in ops["metadata"]:
614
650
  ops["nframes"] = ops["metadata"]["shape"][0]
@@ -625,23 +661,30 @@ def run_plane(
625
661
  "missing frame count (nframes) in ops or metadata, and cannot infer from data"
626
662
  )
627
663
 
628
- processed = run_plane_bin(ops)
629
-
630
- if save_json:
631
- # convert ops dict to JSON serializable and save as ops.json
632
- ops_to_json(ops_file)
664
+ try:
665
+ processed = run_plane_bin(ops)
666
+ except Exception as e:
667
+ print(e)
668
+ processed = False
633
669
 
634
670
  if not processed:
635
671
  print(f"Skipping {ops_file.name}, processing was not completed.")
636
672
  return ops_file
637
673
 
674
+ if save_json:
675
+ # convert ops dict to JSON serializable and save as ops.json
676
+ ops_to_json(ops_file)
677
+
638
678
  raw_file = Path(ops.get("raw_file", plane_dir / "data_raw.bin"))
639
679
  reg_file = Path(ops.get("reg_file", plane_dir / "data.bin"))
640
680
 
641
- if not keep_raw and raw_file.exists():
642
- raw_file.unlink(missing_ok=True)
643
- if not keep_reg and reg_file.exists():
644
- reg_file.unlink(missing_ok=True)
681
+ try:
682
+ if not keep_raw and raw_file.exists():
683
+ raw_file.unlink(missing_ok=True)
684
+ if not keep_reg and reg_file.exists():
685
+ reg_file.unlink(missing_ok=True)
686
+ except Exception as e:
687
+ print(e)
645
688
 
646
689
  save_pc_panels_and_metrics(ops_file, plane_dir / "pc_metrics")
647
690
 
@@ -760,4 +803,4 @@ def run_grid_search(
760
803
  keep_raw=True,
761
804
  force_reg=force_reg,
762
805
  force_detect=force_detect,
763
- )
806
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lbm_suite2p_python
3
- Version: 2.0.3
3
+ Version: 2.0.5
4
4
  Summary: Light Beads Microscopy Pipeline using Suite2p
5
5
  License-Expression: BSD-3-Clause
6
6
  Project-URL: homepage, https://github.com/MillerBrainObservatory/LBM-Suite2p-Python
@@ -12,16 +12,6 @@ Requires-Python: <3.12.10,>=3.12.7
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.md
14
14
  Requires-Dist: mbo_utilities>=2.0.4
15
- Provides-Extra: cpsam
16
- Requires-Dist: cellpose==4.0.6; extra == "cpsam"
17
- Requires-Dist: pytorch; extra == "cpsam"
18
- Requires-Dist: torchaudio; extra == "cpsam"
19
- Provides-Extra: cpu
20
- Requires-Dist: torch>=2.7.0; extra == "cpu"
21
- Requires-Dist: torchvision>=0.22.0; extra == "cpu"
22
- Provides-Extra: cu126
23
- Requires-Dist: torch>=2.7.0; extra == "cu126"
24
- Requires-Dist: torchvision>=0.22.0; extra == "cu126"
25
15
  Dynamic: license-file
26
16
 
27
17
  # Light Beads Microscopy (LBM) Pipeline: Suite2p
@@ -0,0 +1 @@
1
+ mbo_utilities>=2.0.4
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "lbm_suite2p_python"
7
- version = "2.0.3"
7
+ version = "2.0.5"
8
8
  description = "Light Beads Microscopy Pipeline using Suite2p"
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
@@ -21,51 +21,6 @@ dependencies = [
21
21
  "mbo_utilities>=2.0.4",
22
22
  ]
23
23
 
24
- [project.optional-dependencies]
25
- cpsam = ["cellpose==4.0.6", "pytorch", "torchaudio"]
26
- cpu = [
27
- "torch>=2.7.0",
28
- "torchvision>=0.22.0",
29
- ]
30
- cu126 = [
31
- "torch>=2.7.0",
32
- "torchvision>=0.22.0",
33
- ]
34
-
35
- [tool.uv.sources]
36
- torch = [
37
- { index = "pytorch-cu126", extra = "cu126" }, # default
38
- { index = "pytorch-cpu", extra = "cpu" },
39
- ]
40
- torchvision = [
41
- { index = "pytorch-cu126", extra = "cu126" }, # default
42
- { index = "pytorch-cpu", extra = "cpu" },
43
- ]
44
-
45
- [[tool.uv.index]]
46
- name = "pytorch-cpu"
47
- url = "https://download.pytorch.org/whl/cpu"
48
- explicit = true
49
-
50
- [[tool.uv.index]]
51
- name = "pytorch-cu126"
52
- url = "https://download.pytorch.org/whl/cu126"
53
- explicit = true
54
-
55
- [[tool.uv.index]]
56
- name = "pytorch-cu128"
57
- url = "https://download.pytorch.org/whl/cu128"
58
- explicit = true
59
-
60
- [tool.uv]
61
- default-groups = ["all"]
62
- conflicts = [
63
- [
64
- { extra = "cpu" },
65
- { extra = "cu126" },
66
- ],
67
- ]
68
-
69
24
  [dependency-groups]
70
25
  all = [
71
26
  "rastermap",
@@ -95,6 +50,20 @@ docs = [
95
50
  "suite2p_mbo",
96
51
  ]
97
52
 
53
+ [[tool.uv.index]]
54
+ name = "pytorch-cu126"
55
+ url = "https://download.pytorch.org/whl/cu126"
56
+ explicit = true
57
+
58
+ [tool.uv.sources]
59
+ torch = [
60
+ { index = "pytorch-cu126", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
61
+ ]
62
+ torchvision = [
63
+ { index = "pytorch-cu126", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
64
+ ]
65
+
66
+
98
67
  # https://github.com/charliermarsh/ruff
99
68
  [tool.ruff]
100
69
  line-length = 88
@@ -1,14 +0,0 @@
1
- mbo_utilities>=2.0.4
2
-
3
- [cpsam]
4
- cellpose==4.0.6
5
- pytorch
6
- torchaudio
7
-
8
- [cpu]
9
- torch>=2.7.0
10
- torchvision>=0.22.0
11
-
12
- [cu126]
13
- torch>=2.7.0
14
- torchvision>=0.22.0